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
.
eval(new String("2 + 2")); // возвращает объект типа String, содержащий "2 + 2"
eval("2 + 2"); // возвращает 4
Это ограничение легко обойти при помощи toString()
.
var expression = new String("2 + 2");
eval(expression.toString());
Если вы используете eval
косвенно, вызовом его через ссылку, а не просто eval
, в ECMAScript 5 это работает в глобальной области видимости, а не в локальной; это значит, что eval
будет вызван в глобальной области видимости, а код будет выполнен с отсутствием доступа к локальным переменным в пределах области видимости, где он был вызван.
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:
var obj = { a: 20, b: 30 };
var propname = getPropName(); // возвращает "a" или "b"
eval("var result = obj." + propname);
Однако, eval()
здесь не нужен. По факту, использование здесь его удивляет. Вместо него используйте доступ к свойствам, который быстрее и безопаснее:
var obj = { a: 20, b: 30 };
var propname = getPropName(); // возвращает "a" или "b"
var result = obj[propname]; // obj[ "a" ] то же, что и obj.a
Используйте функции вместо исполнения фрагментов кода
У JavaScript функции первого класса, что значит, что вы можете передавать функции как аргументы, хранить их в переменных или свойствах объектов и так далее. Многие DOM API созданы с учётом этого, так что вы можете (и вам следует) писать:
// вместо 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
".
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 и вернёт его.
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()
вернёт значение последнего выполняемого выражения
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
как строковое определение функции, включающее "(" и ")" как префикс и суффикс
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.