ReferenceError в Google Chrome, но не в Firefox (ошибка браузера?)

Этот фрагмент кода

eval(`
    let a = 0;
    function f() {}
    function g() { a; }
    console.log(f);
`);

Ответы

Ответ 1

Похоже, новая ошибка V8! Более минимальный тестовый пример:

eval(`
    var f;
    let a;
    ()=>a
`);
f;

Объявления с переменной областью (которые включают объявления функций верхнего уровня) не получают должным образом подняты из нестрогих вызовов eval, когда вызов также имеет нетривиальное лексическое объявление.

Ответ 2

Тонкая настройка вашего примера показывает, что происходит, а команда немного противоречива, она выглядит как ошибка. Определите a как функцию и запишите его вместо f, а затем посмотрите на консоль. Вы увидите, что закрытие было создано с помощью a, f и g. Поскольку a ссылается на g, а f и g должны быть видны друг другу, это имеет немного смысл. Но eval работает в глобальном масштабе. Поэтому, когда вы пытаетесь получить к ним доступ, вы получаете undefined. Как будто это закрытие невозможно получить откуда угодно.

Try:

eval('let a = function(){}; function f() {};function g(){a;};console.dir(a);'); 

Вы увидите это в консоли:

<function scope>
    Closure
        a: function()
        f: function f()
        g: function g()

Все ваши другие случаи делают ситуацию более ясной и предотвращают проблему:

  • eval не используется: несоответствие области менее очевидно,
  • код внутри eval окружен {}: переменные связаны через область блока.
  • a не указывается в g: нет необходимости в закрытии, если переменные не связаны.
  • let изменено на var: var в глобальной области определяется в глобальный охват. Таким образом, не требуется Closure
  • "использовать строгий" добавляется перед кодом: используйте strict в eval prevent переменные, которые должны быть добавлены в глобальную область действия, так что снова "проще" ручка. Отсутствие несоответствия между необходимостью привязки к глобальным функциям.

Ответ 3

eval(`
    "use strict";
    let a = 0;
    console.log(f);
    function f(){
    }
    function g(){
        a;
    }
`);

Объявления с расширенной областью (let, const, function, class) еще не поддерживаются в строгом режиме