eval()

Предупреждение: Выполнение кода JavaScript с текстовой строки - это невероятный риск для безопасности. Злоумышленнику слишком легко запустить какой угодно код, когда вы используете eval(). Смотрите Никогда не используйте eval()!, ниже.

Метод eval() выполняет JavaScript-код, представленный строкой.

Интерактивный пример

Синтаксис

eval(string)

Параметры

string

Строка, представленная JavaScript выражением, оператором или последовательностью операторов. Выражение может содержать переменные и свойства существующих объектов.

Возвращаемое значение

Возвращает значение выполнения кода, переданного в функцию в виде строки. Если код не возвращает ничего - будет возвращено значение undefined.

Описание

eval() - функция глобального объекта.

Аргумент функции eval() - строка. eval() исполняет содержащееся в строке выражение, один или несколько операторов JavaScript. Не стоит вызывать eval() для определения значения арифметического выражения; JavaScript вычисляет их автоматически.

eval() можно использовать для вычисления значения арифметического выражения, записанного в строковом виде, на более поздней стадии исполнения. Предположим, существует переменная x. Можно отложить вычисление выражения, в котором содержится х, если присвоить переменной это выражение в виде строки (допустим, "3 * x + 2"), а затем вызвать eval() в более поздней точке кода.

Если аргумент, переданный eval(), не является строкой, eval() возвращает его неизменным. В следующем примере определён конструктор String, и eval() не вычисляет значение выражения, записанного в строковом виде, а возвращает объект типа String.

js
eval(new String("2 + 2")); // возвращает объект типа String, содержащий "2 + 2"
eval("2 + 2"); // возвращает 4

Это ограничение легко обойти при помощи toString().

js
var expression = new String("2 + 2");
eval(expression.toString());

Если вы используете eval косвенно, вызовом его через ссылку, а не просто eval, в ECMAScript 5 это работает в глобальной области видимости, а не в локальной; это значит, что eval будет вызван в глобальной области видимости, а код будет выполнен с отсутствием доступа к локальным переменным в пределах области видимости, где он был вызван.

js
function test() {
  var x = 2,
    y = 4;
  console.log(eval("x + y")); // Прямой вызов, использует локальную области видимости, результат - 6
  var geval = eval;
  console.log(geval("x + y")); // Непрямой вызов, использует глобальную область видимости, бросит ReferenceError, т.к. `x` - не определён
}

Не используйте eval без необходимости!

eval() - опасная функция, которая выполняет код, проходящий со всеми привилегиями вызывателя. Если вы запускаете eval() со строкой, на которую могут влиять злоумышленники, то вы можете запустить вредоносный код на устройство пользователя с правами вашей веб-страницы/расширения. Наиболее важно, код третьей стороны может видеть область видимости, в которой был вызван eval(), что может может привести к атакам, похожим на Function.

Также eval(), как правило, медленнее альтернатив, так как вызывает интерпретатор JS, тогда как многие другие конструкции оптимизированы со��ременными JS движками.

Есть безопасные (и быстрые!) альтернативы eval() для общих случаев использования.

Доступ к свойствам

Вам не следует использовать eval(), чтобы конвертировать имена свойств в свойства. Рассматривая следующий пример, где свойство объекта используемое для доступа неизвестно до выполнения кода. Это можно сделать с eval:

js
var obj = { a: 20, b: 30 };
var propname = getPropName(); // возвращает "a" или "b"

eval("var result = obj." + propname);

Однако, eval() здесь не нужен. По факту, использование здесь его удивляет. Вместо него используйте доступ к свойствам, который быстрее и безопаснее:

js
var obj = { a: 20, b: 30 };
var propname = getPropName(); // возвращает "a" или "b"
var result = obj[propname]; //  obj[ "a" ] то же, что и obj.a

Используйте функции вместо исполнения фрагментов кода

У JavaScript функции первого класса, что значит, что вы можете передавать функции как аргументы, хранить их в переменных или свойствах объектов и так далее. Многие DOM API созданы с учётом этого, так что вы можете (и вам следует) писать:

js
// вместо setTimeout(" ... ", 1000) :
setTimeout(function() { ... }, 1000);

// вместо elt.setAttribute("onclick", "...") использовать:
elt.addEventListener("click", function() { ... } , false);

Замыкания также полезны как способ создания функций с параметрами без конкатенации строк.

Разбор JSON (конвертирование строк в JavaScript объекты)

Если строка, переданная в eval(), содержит данные (к примеру, массив: "[1, 2, 3]"), а не код, вам следует рассмотреть JSON, позволяющий строке использовать подмножество JavaScript синтаксиса для представления данных. Смотрите также: Загрузка JSON и JavaScript в расширениях.

Заметьте, что синтаксис JSON ограничен в сравнении с JavaScript синтаксисом, многие валидные JavaScript литералы не распарсятся в JSON. К примеру, лишние запятые в конце выражений не разрешены в JSON, а имена свойств (ключи) в объектах должны быть в двойных кавычках. Будьте уверены использовать сериализацию JSON для создания строк, которые потом будут разбираться как JSON.

Передавайте данные вместо кода

К примеру, расширение, созданное изменять содержимое веб-страниц, должно иметь правила, определённые в XPath, а не JS коде.

Выполняйте код с ограниченными правами

Если выполнять код всё-таки необходимо, желательно это делать с уменьшенными привелегиями. Этот совет подходит, главным образом, к расширениям и XUL приложениям, которые могут использовать Components.utils.evalInSandbox.

Примеры

Использование eval

В следующем коде оба выражения содержат eval(), возвращающий 42. Первое определяется строкой "x + y + 1"; второе - строкой "42".

js
var x = 2;
var y = 39;
var z = "42";
eval("x + y + 1"); // возвращает 42
eval(z); // вернёт 42

Использование eval для исполнения строки, содержащей операторы JavaScript

Следующий пример использует eval() для получения значения выражения str. Эта строка состоит из JavaScript выражений, печатающих в консоль, и, если x равен пяти, призывающих z значение 42, или 0 в противном случае. Когда второе выражение будет исполнено, eval() будет считать выражения выполненными, а также это установит значение выражению переменной z и вернёт его.

js
var x = 5;
var str = "if (x == 5) {console.log('z is 42'); z = 42;} else z = 0; ";

console.log("z is ", eval(str));

Последнее выражение выполняется

eval() вернёт ��начение последнего выполняемого выражения

js
var str = "if ( a ) { 1+1; } else { 1+2; }";
var a = true;
var b = eval(str); // вернёт 2

console.log("b is : " + b);

a = false;
b = eval(str); // вернёт 3

console.log("b is : " + b);

eval как строковое определение функции, включающее "(" и ")" как префикс и суффикс

js
var fctStr1 = "function a() {}";
var fctStr2 = "(function a() {})";
var fct1 = eval(fctStr1); // вернёт undefined
var fct2 = eval(fctStr2); // вернёт функцию

Спецификации

Specification
ECMAScript Language Specification
# sec-eval-x

Совместимость с браузерами

BCD tables only load in the browser

Gecko-специфичные замечания

  • Исторически eval() имел второй необязательный аргумент, указывающий на то, в контексте какого объекта будет выполняться выражение. Этот аргумент не был стандартизован и был удалён из SpiderMonkey в Gecko 1.9.1 (Firefox 3.5). См. Firefox bug 442333.

Смотрите также