(функция eval() {}) выдает синтаксическую ошибку, если тело функции находится в строгом режиме? - программирование
Подтвердить что ты не робот

(функция eval() {}) выдает синтаксическую ошибку, если тело функции находится в строгом режиме?

Почему этот код выдает ошибку?

// global non-strict code
(function eval () { 'use strict'; });

Live demo: http://jsfiddle.net/SE3eX/1/

Итак, что мы имеем здесь, это именованное функциональное выражение. Я хотел бы прямо указать, что это выражение функции появляется в нестандартном коде. Как вы можете видеть, его тело функции является строгим кодом.

Правила строгого режима находятся здесь: http://ecma-international.org/ecma-262/5.1/#sec-C

Соответствующая марка - это одна (последняя в списке):

Это SyntaxError для использования в строгом режиме кода идентификаторы eval или аргументы как идентификатор FunctionDeclaration или FunctionExpression или как формальное имя параметра (13.1). Попытка динамически определить такую ​​строгую функцию режима с помощью конструктора Function (15.3.2) вызовет исключение SyntaxError.

Обратите внимание, что это правило применяется только в том случае, если само выражение/выражение функции отображается в строгом коде, чего нет в моем примере выше.

Но он все еще выдает ошибку? Почему?

4b9b3361

Ответ 1

§13.1 описывает, что должно произойти в таких случаях, как ваше:

  • Это SyntaxError, если какое-либо значение идентификатора встречается более одного раза в FormalParameterList строгого режима FunctionDeclaration или ВыражениеФункции.
  • Это SyntaxError, если идентификатор "eval" или "аргументы" идентификатора встречается внутри: - FormalParameterList строгого режима FunctionDeclaration или FunctionExpression.
  • Это SyntaxError, если идентификатор "eval" или "аргументы" идентификатора происходит как идентификатор строгого режима FunctionDeclaration или FunctionExpression.

Акцент мой. Идентификатор функции строгого режима eval, поэтому a SyntaxError. Игра закончилась.


Чтобы понять, почему вышесказанное является выражением функции строгого режима, посмотрите на семантические определения в §13 (Определение функции):

Производство FunctionExpression: function Идентификатор opt( FormalParameterList opt) { FunctionBody } оценивается следующим образом:

  • Возвращает результат создания нового объекта Function, указанного в 13.2, с параметрами, указанными FormalParameterListopt и телом указанный функцией FunctionBody. Перейдите в Лексическую среду выполнение контекста выполнения в качестве области действия. Передать истину как Строгий если выражение FunctionExpression содержится в строгом коде или если его FunctionBody - это строгий код.

Акцент мой. Вышеприведенное показывает, как выражение функции (или объявление) становится строгим. То, что он говорит (на простом английском языке), состоит в том, что FunctionExpression strict в двух сценариях:

  • Он вызвал из контекста use strict.
  • Его тело функции начинается с use strict.

Ваше замешательство возникает из-за того, что только тело функции strict, когда на самом деле все выражение функции strict. Ваша логика, хотя и интуитивно понятна, не работает JS.


Если вам интересно, почему ECMAscript работает таким образом, это довольно просто. Предположим, что мы имеем:

// look ma, I'm not strict
(function eval() {
     "use strict";
     // evil stuff
     eval(); // this is a perfectly legal recursive call, and oh look...
             // ... I implicitly redefined eval() in a strict block
     // evil stuff
})();

К счастью, приведенный выше код будет выдаваться, потому что все выражение функции помечено как strict.

Ответ 2

Отличный вопрос!

Чтобы найти ответ на вашу проблему, вам действительно нужно посмотреть процесс для объявления функции (в частности, шаги 3-5 - - добавлено выделение):

  • ...
  • ...
  • Вызвать конкретный метод CreateImmutableBinding для envRec, передавая значение String идентификатора в качестве аргумента.
  • Пусть замыкание является результатом создания нового объекта Function, указанного в 13.2, с параметрами, указанными FormalParameterList opt и телом, указанным FunctionBody. Перейдите в funcEnv как область действия. Передать true, как флаг Strict, если выражение Function содержится в строгом коде или , если его FunctionBody является строгим кодом.
  • Вызвать конкретный метод InitializeImmutableBinding для envRec, передавая значение String идентификатора и закрытия в качестве аргументов.

Итак, что происходит, так это то, что ваше использование eval не является проблемой, когда привязка создается на шаге 3, но как только она достигает шага 5, она пытается инициализировать привязку eval в строгой лексической среде ( т.е. присваивать что-то eval), что недопустимо, потому что мы находимся в строгом контексте после шага 4.

Помните, что ограничение не на инициализацию новой переменной eval. Он использует его как оператор LeftHandSideExpression оператора присваивания, что и происходит на шаге 5 процесса объявления функции.

UPDATE:

Как отметил @DavidTitarenco, это явно рассматривается в разделе 13.1 (в дополнение к неявному ограничению в разделе 13).

Ответ 3

Я предполагаю, что он выдает ошибку, потому что внутри функции eval будет указывать на саму функцию, которая теперь нарушает строгий режим.