Змінні let, const (і класи) теж «піднімаються» на початок своєї області видимості, але не ініціалізуються. Від початку блоку до рядка оголошення змінна існує, але звертання до неї кидає ReferenceError. Цей проміжок називають тимчасовою мертвою зоною (temporal dead zone).
{
console.log(price); // ReferenceError: Cannot access 'price' before initialization
let price = 100;
}
З var поведінка інша - змінна ініціалізується як undefined, і помилка тихо проходить:
console.log(total); // undefined
var total = 100;
Чому це «тимчасова», а не «просторова» зона. Важливий момент виконання, а не позиція в тексті:
function showPrice() {
console.log(price); // функцію оголошено вище за let...
}
let price = 100;
showPrice(); // ...але викликано після ініціалізації - працює
Неочевидні випадки:
typeofне рятує. Для неоголошеної змінноїtypeof xповертає'undefined', але для змінної в TDZ - кидаєReferenceError;- затінення:
const limit = 10;
function check() {
console.log(limit); // ReferenceError: внутрішня limit у TDZ
const limit = 20;
}
Внутрішнє оголошення «закриває» зовнішнє для всього блоку, а не лише від свого рядка;
- параметри за замовчуванням:
function f(a = b, b = 1) {}- при викликуf()параметрbще в TDZ; - класи:
new User()до рядкаclass User {}теж кидає помилку, на відміну від функцій.
Навіщо це зроблено так:
- помилка доступу до неініціалізованої змінної видна одразу, а не перетворюється на загадкове
undefined; constповинна мати рівно одне значення - побачити її «до» присвоєння було б порушенням цього правила.
Практичний висновок: оголошувати змінні до використання, на початку блоку чи безпосередньо перед ним. Помилки TDZ найчастіше трапляються при циклічних імпортах модулів: модуль звертається до експортованого const іншого модуля, який ще не встиг виконатися.