Я могу только догадываться, но мне кажется, что ES5-strict говорит, что eval
и arguments
следует рассматривать как сырой синтаксис, а не идентификаторы. Разумно, что эти две функции должны быть реализованы на синтаксическом уровне, потому что у них есть поведение Amazing Funky Magic, которое невозможно воспроизвести с помощью нормальной функции.
(В частности eval
может писать локальные переменные в функция, которая его вызывает, и запись в arguments
странно изменяет значения локальных переменных, соответствующих аргументам. Хотя это поведение, кажется, уходит в строгом режиме, к счастью.)
По соображениям совместимости, ES5 не может реально сделать eval
и arguments
синтаксическим. Таким образом, они делают все возможное, что означает, что идентификатор arguments
всегда относится к магии arguments
, а идентификатор eval
всегда относится исключительно к магии eval
.
Он также может улучшить возможности для оптимизации, если JS-двигатели могут быть уверены, что функция содержит магию.
bobince в основном правильный. (Я работаю над SpiderMonkey, JS-движком Mozilla, внедрил в него различные части ES5 и следую дискуссиям ECMAScript по мере того, как позволяет время.) Вы (разработчики и читатели оба) действительно хотите eval
быть каноническим eval
и вы хотите arguments
быть каноническим arguments
. Используя строгий режим, вы можете в основном получить это.
Но я укажу, что ограничения ES5 здесь не так велики, как хотелось бы. Во-первых, и слегка исправить bobince, даже при строгом режиме, вы не можете быть уверены eval
- это оригинальная функция eval
:
"use strict";
this.eval = function() { return "ohai"; };
eval("7 + 10"); // "ohai"
Это известная (среди поклонников JS) ошибка глобального объекта: эти сценарии используют глобальный объект, совместно используемый сценариями, именными и модифицируемыми, для разрешения имен. Если вы не могли ссылаться на объект, где глобальные переменные связаны, у вас не было бы этой проблемы. Скорее всего, ES6 исправит это с помощью другой системы выбора (возможно, внеполосного типа типа MIME, но пока неясно), всегда привязанного ко всем скриптам.
Но даже без именного, изменяемого глобального объект, у вас все еще есть проблемы, потому что строгий режим может быть ограничен функциями:
function outer()
{
var eval = function() { return "kthxbai"; };
function inner()
{
"use strict";
return eval("2 + 5");
}
return inner();
}
outer(); // "kthxbai"
Эти проблемы существуют даже при наличии строгого режима, и они не уйдут до ES6 как можно раньше, так как он, вероятно, удалит глобальный объект и безоговорочно будет применять ограничения строгого режима.
Таким образом, eval
в строгом режиме все еще немного странно, поскольку он может ссылаться на не-eval. Но обработка это не имеет большого значения - во время выполнения реализация может проверить реальную eval
, и если это не так, просто выполните то, что она сделала бы, если бы синтаксис использовал имя, отличное от eval
. Это требует особого использования выражения типа eval(...)
. Но любая хорошая реализация сделала это в любом случае из-за нестатически наблюдаемого поведения eval
(мутируя локальные переменные и аргументы, введя новые переменные [теперь де-fanged в строгом режиме - объявления переменных в строгом режиме eval code являются локальными к eval-коду] и т. д.), поэтому это не является реальным бременем.
Стоит отметить, что ни одно из этого не относится к arguments
как к фальшивой специальной форме. Либо у вас есть строгий режим с помощью области функций, и в этом случае вы увидите , что функция arguments
, а не arguments
, назначенная во внешней области, или вы имеете ее в виде глобальный масштаб, и в этом случае arguments
не имеет особого поведения. (Зачем запрещать мутацию arguments
в глобальном коде строгого режима? Вероятно, простота, а также заставляют разработчиков относиться к ним как к большей части особой формы повсюду, но я не уверен.)
eval
/ arguments
по-прежнему разрешены как имена ярлыков в строгом режиме?
– Šime Vidas
24 September 2012 в 01:59
eval
/ arguments
были запрещены как имена переменных в коде строгого режима. :-)
– Jeff Walden
25 September 2012 в 18:25
eval
как "прямой" или "косвенный". Прямое eval происходит только через выражение видаeval(...)
. Эта форма делает то, что всегда делается - вводить новые привязки, быть злыми и так далее. Непрямой eval never i> влияет на локальную область действия - вместо этого он вынужден действовать в глобальной области. С этим изменением вы точно знаете, что может произойти в любой функции, которая не включает прямое eval, - и если это так, вы сильно угаснете. Технически ES3 позволяет реализациям запрещать косвенную оценку, но мало кто сделал, и, возможно, JScript.NET не был одним. – Jeff Walden 25 December 2010 в 10:58eval
влиял на глобальную сферу действия de-fangs самой пагубной формойeval
. (Прямойeval
невелик, но он, по крайней мере, обнаруживается, так что его плохое поведение может быть предотвращено.) Косвенныйeval
все еще может изменить глобальную область действия, true. Но все, что угодно в функции, может сделать так, что невозможно предсказать статически. Ссылки на глобальные имена никогда не могут быть оптимизированы так же, как локальные имена, а косвенныеeval
не меняют вопросов. Только ES6 удаление глобального объекта, если это произойдет, может сделать это. – Jeff Walden 25 December 2010 в 11:08eval
не всегда ссылается на функцию, которая оценивает свой аргумент в строгом режиме. Рассмотрим эту нестрогую программу, содержащую строгую функцию режима:eval = alert; function foo(s) { "use strict"; eval(s); }
. – Mike Samuel 25 December 2010 в 12:41