Почему eval не может использоваться как переменная в строгом режиме [duplicate]

4
задан Shog9 18 August 2010 в 00:36
поделиться

2 ответа

Я могу только догадываться, но мне кажется, что ES5-strict говорит, что eval и arguments следует рассматривать как сырой синтаксис, а не идентификаторы. Разумно, что эти две функции должны быть реализованы на синтаксическом уровне, потому что у них есть поведение Amazing Funky Magic, которое невозможно воспроизвести с помощью нормальной функции.

(В частности eval может писать локальные переменные в функция, которая его вызывает, и запись в arguments странно изменяет значения локальных переменных, соответствующих аргументам. Хотя это поведение, кажется, уходит в строгом режиме, к счастью.)

По соображениям совместимости, ES5 не может реально сделать eval и arguments синтаксическим. Таким образом, они делают все возможное, что означает, что идентификатор arguments всегда относится к магии arguments, а идентификатор eval всегда относится исключительно к магии eval.

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

7
ответ дан bobince 28 August 2018 в 08:43
поделиться
  • 1
    Действительно, когда мы работали над JScript.NET, мы часто хотели, чтобы был способ абсолютно положительно гарантировать, что (1) вызывает что-то, называемое «eval». вызывал eval и (2) ссылался на то, что не называлось «eval». не вызывал eval. Конструкция ECMAScript очень затрудняет определение статики и поэтому затрудняет запись оптимизирующего компилятора. Я больше не работаю в техническом комитете более десяти лет и поэтому не могу говорить окончательно об их мотивах, но был ли я в этом комитете еще раз, я бы, конечно, хотел бы именно такое ограничение. – Eric Lippert 18 August 2010 в 00:41
  • 2
    ES5 изменяет eval как "прямой" или "косвенный". Прямое eval происходит только через выражение вида eval(...). Эта форма делает то, что всегда делается - вводить новые привязки, быть злыми и так далее. Непрямой eval never влияет на локальную область действия - вместо этого он вынужден действовать в глобальной области. С этим изменением вы точно знаете, что может произойти в любой функции, которая не включает прямое eval, - и если это так, вы сильно угаснете. Технически ES3 позволяет реализациям запрещать косвенную оценку, но мало кто сделал, и, возможно, JScript.NET не был одним. – Jeff Walden 25 December 2010 в 10:58
  • 3
    Итак, продолжая (заканчивается персонажей), требуя, чтобы косвенный eval влиял на глобальную сферу действия de-fangs самой пагубной формой eval. (Прямой eval невелик, но он, по крайней мере, обнаруживается, так что его плохое поведение может быть предотвращено.) Косвенный eval все еще может изменить глобальную область действия, true. Но все, что угодно в функции, может сделать так, что невозможно предсказать статически. Ссылки на глобальные имена никогда не могут быть оптимизированы так же, как локальные имена, а косвенные eval не меняют вопросов. Только ES6 удаление глобального объекта, если это произойдет, может сделать это. – Jeff Walden 25 December 2010 в 11:08
  • 4
    Идентификатор eval не всегда ссылается на функцию, которая оценивает свой аргумент в строгом режиме. Рассмотрим эту нестрогую программу, содержащую строгую функцию режима: eval = alert; function foo(s) { "use strict"; eval(s); }. – Mike Samuel 25 December 2010 в 12:41

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 в глобальном коде строгого режима? Вероятно, простота, а также заставляют разработчиков относиться к ним как к большей части особой формы повсюду, но я не уверен.)

10
ответ дан Jeff Walden 28 August 2018 в 08:43
поделиться
  • 1
    Вы могли бы знать, почему eval / arguments по-прежнему разрешены как имена ярлыков в строгом режиме? – Šime Vidas 24 September 2012 в 01:59
  • 2
    Я не знаю, но в любом случае я очень сомневался в ответе на вопрос, исходя из причин, по которым eval / arguments были запрещены как имена переменных в коде строгого режима. :-) – Jeff Walden 25 September 2012 в 18:25
Другие вопросы по тегам:

Похожие вопросы: