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)  // вернёт функцию

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

Спецификация Статус Комментарий
ECMAScript 1st Edition. Стандарт Изначальное определение.
ECMAScript 5.1 (ECMA-262)
Определение 'eval' в этой спецификации.
Стандарт  
ECMAScript 2015 (6th Edition, ECMA-262)
Определение 'eval' в этой спецификации.
Стандарт  

Поддержка браузерами

Особенность Chrome Firefox (Gecko) Internet Explorer Opera Safari
Базовая поддержка (Да) (Да) (Да) (Да) (Да)
Особенность Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Базовая поддержка (Да) (Да) (Да) (Да) (Да) (Да)

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

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

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

Метки документа и участники

 Внесли вклад в эту страницу: lazy-code, Kesantielu, pankov, BychekRU, KTatyana, Bogdan92
 Обновлялась последний раз: lazy-code,