Это ошибка Chrome или мое использование use strict и eval недействительно?

Этот код работает с оповещениями "ok" во всех браузерах, кроме Chrome:

eval("var outer = 0; function test() {'use strict'; outer = 1; } test(); alert('ok');");

(Попробуйте на jsfiddle).

Все, что я делаю, это ссылаюсь на внешнюю переменную из функции 'use strict', и все это в контексте eval. Хром говорит

Uncaught ReferenceError: outer is not defined 

Примечание. Первоначально я столкнулся с этим при использовании devtool: 'eval' в Webpack.


person Dan Abramov    schedule 21.08.2014    source источник
comment
Ваша скрипка настроена на использование очень удивительного значения по умолчанию jsFiddle, заключающегося в переносе всего вашего кода в обработчик window.onload. (Второй раскрывающийся список слева.) Если вы отключите это, код (в глобальном масштабе) будет работать так, как ожидалось: jsfiddle.net/rokkkjcs/2 Я также проверил это без использования jsFiddle (на случай, если jsFiddle делает что-то странное). Таким образом, возникает вопрос: почему должно иметь значение, происходит ли eval внутри функции или в глобальной области видимости? В любом случае, test должен закрыться через outer... В. о. странно.   -  person T.J. Crowder    schedule 21.08.2014
comment
О, и я упоминал, что он работает (даже если он обернут в функцию), когда вы запускаете его непосредственно из консольного REPL? Все любопытнее и любопытнее...   -  person T.J. Crowder    schedule 21.08.2014
comment
Использование eval неполиткорректно.   -  person frenchie    schedule 22.08.2014
comment
@frenchie Вы прочитали, почему я его использую?   -  person Dan Abramov    schedule 22.08.2014


Ответы (2)


Чтобы упростить задачу: http://jsfiddle.net/rokkkjcs/6/

eval("var outer=0;");
function test() {'use strict'; outer = 1; } 
test(); 
alert('ok');

И объяснение такое:

Нестрогий код может использовать функцию «eval» для добавления новых переменных в окружающую область. До встроенной поддержки JSON в браузерах eval обычно (и небезопасно) использовался для создания объектов из строк. Построенные объекты затем стали частью окружающего пространства. В строгом режиме eval не может вводить новые переменные. При выполнении в строгом режиме следующий фрагмент кода не будет вводить переменную bar в окружающую область. Примечание: если функция, содержащая «eval», выполняется в строгом режиме, то код внутри функции «eval» также выполняется в строгом режиме.

Дополнительная информация: http://cjihrig.com/blog/javascripts-strict-mode-and-why-you-should-use-it/

person ovi    schedule 21.08.2014
comment
Я не совсем уверен, что понимаю вас здесь. Вы утверждаете, что ваш пример эквивалентен моему? Можете ли вы объяснить, почему? - person Dan Abramov; 21.08.2014
comment
Единственная проблема заключается в добавлении новой переменной в окружающую область с помощью eval(). В строгом режиме эта переменная будет недоступна. Он работает без обертки, потому что тогда он находится в глобальной области видимости. - person ovi; 21.08.2014
comment
Но eval не выполняется в строгом режиме, не так ли? - person Bergi; 24.08.2014

На самом деле eval создает переменные или изменяет переменные в области видимости, где она определена, независимо от того, используете ли вы val или нет. Или, другими словами, по умолчанию у него нет собственной области видимости.

Итак, когда вы делаете это

eval("var outer = 0;");
console.log(outer); //0

вы создаете переменную во внешней области. Удивительно, но это работает так же и в хроме - и не имеет значения, используется ли window.onload или нет.

Чтобы сделать eval собственной областью действия, вы должны сделать следующее:

eval("'use strict'; var outer = 0;"); 
console.log(outer); //Uncaught ReferenceError: outer is not defined 

Теперь для eval есть отдельная область видимости. С 'use strict' в eval ваш код будет работать в chrome и не позволит переопределять переменные вне eval.

eval("'use strict'; var outer = 0; function test() {'use strict'; outer = 1; } test(); alert('ok');");

Итак, эта часть отвечает, как вы можете избежать ошибок.

Вторая часть, которая меня очень заинтересовала, но я не смог найти ответ сам.

Возникает вопрос, почему ваш код выдает ошибку в хроме, в то время как это работает в хроме (что означает, что создается глобальная переменная):

window.onload = function() {
   eval("var outer = 0; function test(){console.log(outer); } test();");
}

А также почему это происходит только с window.onload.

person Elena    schedule 21.08.2014