Това грешка в Chrome ли е или моето използване на use strict и eval е невалидно?

Този код работи с предупреждения „ОК“ във всички браузъри с изключение на Chrome:

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

(Опитайте на jsfiddle).

Всичко, което правя, е да препращам към външна променлива от 'use strict' функция, всичко това в eval контекст. Chrome казва

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 прави нещо странно). Така че възниква въпросът: Защо трябва да има значение дали оценката се случва в рамките на функция или в глобален обхват? Така или иначе, test трябва да затвори над outer... V. v. странно.   -  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

създавате променлива във външния обхват. Изненадващо, това работи по същия начин и в chrome - и няма значение дали 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');");

Така че тази част отговаря как можете да избегнете грешка.

Втората част, която много ме интересува, но не можах да намеря отговор сам.

Въпросът е следният, защо вашият код извежда грешка в chrome, докато това работи в chrome (което означава, че глобалната променлива е създадена):

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

И също защо се случва само с window.onload.

person Elena    schedule 21.08.2014