2016-01-13 6 views
3

Я пытаюсь создать простой REPL, убрав строки, предоставленные пользователем. Похоже, что он работает по большей части, за исключением входных данных, таких как «function f() {...}», которые не влияют на то, какие функции видны в будущих оценках. Поиграв с ним немного, я могу только заключить, что я вообще не понимаю eval. Вот короткий отрывок демонстрирует некоторые загадочные поведения:Определения функции определения уязвимости (... в JavaScript)

var xeval = eval; 

function silly() {} 

eval("function good() {}"); 

function baffleMe() { 
    eval("alsoGood = function() {}"); 
    eval("function notSoGood() {}"); 
    xeval("function hope() {}"); 
    xeval("function crushedHope() { silly(); }"); 
} 

baffleMe(); 

good();   // Okay. 
alsoGood();  // Okay. 
notSoGood(); // ReferenceError: notSoGood is not defined 
hope();   // Why does this even work? 
crushedHope(); // ReferenceError: silly is not defined 

Может кто-нибудь объяснить эти результаты, пожалуйста? (Возпроизводимые как в последней Chrome и Firefox)

[EDIT]

Для уточнения, последний вызов не выполняется только тогда, когда код выполняется в консоли Javascript или инструменты, такие как JSFiddle, но не тогда, когда встроенный в сценарии тег. Комментарии к принятому ответу содержат объяснение этого.

+0

См. Разницу между 'window.eval' (' global.eval' в узле) и 'eval' – elclanrs

+0

тесно связан: [глобальный.eval не может посещать переменные в лексической области] (http://stackoverflow.com/q/31459180/710446) – apsillers

+0

Если вы собираетесь сделать REPL, вы должны поместить оценки строк в выражения 'try catch' , и если сообщение об ошибке «Неожиданный конец ввода», тогда запрос на получение большего количества кода до тех пор, пока не будет выполнен «eval» или не приведет к другой ошибке. –

ответ

1

Я попытаюсь объяснить:

Хорошо оценивается в глобальной области:

good();   // Okay. 

Alsogood не имеет никакого определения Var, таким образом, определяется на глобальном масштабе:

alsoGood();  // Okay. 

NotSoGood определяется внутри области функций, поэтому не существует в глобальном масштабе:

notSoGood(); // ReferenceError: notSoGood is not defined 

Надежда оценивается ссылкой закрывающего Eval на глобальном масштабе, таким образом, она оценивается на глобальном масштабе:

hope();   // Why does this even work? 

CrushedHope такой же, как надежда, но глупо должно быть определено в этом случае:

crushedHope(); // ReferenceError: silly is not defined 

Как уже упоминалось в комментариях ниже, глупо не определено в этом вопросе при использовании JSFiddle и когда код обернут window.onload.

+0

Но почему глупо не видно в измельченной Надежде? – user3026691

+0

@ user3026691 'crushedHope' не создает ошибку, которую вы описываете, когда я тестирую ее в консолях Chrome и Firefox. Где вы видите эту ошибку? – apsillers

+1

@ user3026691 Ах, я вижу проблему: если ваш код не является глобальным (например, завернутый внутри '(function() {...})()' IIFE, тогда 'глупо' не является глобальным. , 'crushedHope' * * глобально, поэтому он не может видеть вашу локально определенную' глупую' функцию внутри IIFE. – apsillers

1

Это особенность ECMAScript5. Для quote MDN:

Если вы используете функцию Eval косвенно, запустив его с помощью ссылки, кроме Eval, по состоянию на ECMAScript 5 работает в глобальном масштабе, а не местного масштаба; это означает, например, что декларации функций создают глобальные функции и что оцениваемый код не имеет доступа к локальным переменным в пределах области, где он вызывается.

Таким образом, непосредственный вызов eval() создает функцию в локальной области. (Использование метода a=something автоматически создает глобальный.) Но когда вы косвенно вызываете его по xeval(), он получает оценку по всему миру.

Ваш окончательный результат silly не определен, зависит от области, в которой вы оцениваете. Если вы находитесь в консоли, она, похоже, имеет разную область. Если вы создаете тестовую HTML-страницу, она работает правильно.

Смежные вопросы