Использует ли 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 Инициализация переменной?