Что происходит при обращении к переменной var и let до объявления в JavaScript
Что проверяют
Понимаете ли вы механизм, а не заучили табличку «var даёт undefined, let даёт ошибку». Главная ловушка: многие отвечают, что let не поднимается. Следом часто дают задачку с затенением переменной во вложенном блоке или с typeof.
Как отвечать
Поднимаются (hoisting) оба объявления: движок регистрирует имена ещё до выполнения кода области видимости. Разница в том, как их инициализируют.
var: при создании функциональной области сразу получает значениеundefined. Чтение до строки объявления вернётundefined, присваивание тоже сработает;letиconst: имя создаётся в блоке, но остаётся неинициализированным, пока выполнение не дойдёт до объявления. Этот промежуток называется временной мёртвой зоной (TDZ), любое обращение в нём бросаетReferenceError: Cannot access 'x' before initialization;- необъявленная переменная: тоже
ReferenceError, но с текстомx is not defined. По сообщению видно, TDZ это или опечатка; classведёт себя какlet, а объявление функции поднимается целиком вместе с телом.
Хорошо показать, что TDZ временная, а не пространственная. Функция, объявленная выше let x, может читать x, если её вызвали уже после объявления. А вот такой код падает, хотя снаружи x есть:
let x = 1; { console.log(x); let x = 2; }
Внутренний x затеняет внешний на весь блок, и первая строка блока попадает в его TDZ.
Ещё два отличия, которые стоит упомянуть: var игнорирует блоки и видна во всей функции, а на верхнем уровне скрипта становится свойством window; let в цикле for создаёт новую привязку на каждой итерации, отсюда классическая задача с setTimeout в цикле.
Где спотыкаются
Говорят, что let и const не поднимаются. Если бы не поднимались, в примере с затенением вывелась бы единица.
Считают typeof безопасным всегда. Для необъявленного имени он вернёт строку "undefined", а для переменной в TDZ бросит ReferenceError.
Путают объявление функции с функциональным выражением: var f = function () {} до присваивания равно undefined, и вызов даёт TypeError: f is not a function.