Использует ли Javascript динамическое разрешение имен?

Это мой способ проверить, есть ли у языка динамическое разрешение имен.

function foo() {
    function bar() {
        print a
    }
    var a = 10
    bar()
}

Если язык использует динамическое разрешение имен, код должен вывести 10. В противном случае он должен выдать неопределенную ошибку.

Javascript печатает 10. Но Javascript использует переменный подъем, который перемещает var a наверх foo и лишает законной силы мой тест.

Изменить: Если бы мы могли удалить переменные в JS, следующий тест был бы отличным тестом:

var a = 5
function foo() {
    var a = 10
    function bar() {
        print a
    }
    delete a
    bar()
}
foo()

Если JS статически разрешает имена, бар a ссылки фу a, С Фу a удаляется (если бы это было возможно), бар будет печатать undefined,

Если JS динамически разрешает имена, бар a будет выглядеть динамически при вызове bar(). Так как foo's a уже удален на этом этапе, поиск найдет глобальный a, а bar выведет 5.

1 ответ

Решение

Использует ли Javascript динамическое разрешение имен?

Да. Рассмотрим следующий пример:

eval("var foo = 'foo';");

console.log(foo);
// > "foo"

Переменная foo не привязан к лексической среде до времени выполнения (из-за eval() утверждение), но тот факт, что ошибка не генерируется (и код работает), демонстрирует, что имя разрешается динамически.


Но Javascript использует переменную hoisting, которая перемещает var a в верхнюю часть foo и делает мой тест недействительным.

Примечание: может быть, вы просто говорите, что подъем мешает тесту, который вы пытаетесь выполнить? Если так, пожалуйста, проигнорируйте остальную часть этого ответа...

Такое поведение на самом деле объясняется подъемом, а не аннулируется им. То есть,

  • Как вы указали, из-за подъема, переменная a создается (но еще не назначен) на самом верху foo() функция.

  • Далее у вас есть объявление функции. Как это случается, объявления функций также поднимаются наверх.

  • Далее вы назначаете значение 10 в a, Обратите внимание, что это происходит до того, как вы на самом деле bar(),

  • Наконец, вы на самом деле вызываете bar() в какой момент a уже было присвоено значение 10, в результате чего 0 распечатывается.

Объединяя это все вместе, ваш foo() Функция ведет себя так же, как если бы она была написана следующим образом:

function foo() {
    // hoisted
    var a;

    // also hoisted
    function bar() {
        // due to hoisting, `a` is lexically in scope here
        console.log(a);
    }

    // the actual assignment
    a = 10

    // the invocation
    bar()
}

Мне довелось дать довольно подробное объяснение разницы между объявлениями и присваиваниями / инициализацией в ответе только вчера вечером. Это также объясняет многое из наблюдаемого здесь поведения: Объявление vs Инициализация переменной?

Другие вопросы по тегам