Пошук уроків, статей та іншого контенту
Чому var і function поводяться інакше за let і const, і що таке тимчасова мертва зона.
Перед виконанням коду рушій проходить область видимості й «реєструє» усі оголошення змінних і функцій — цей крок називається hoisting (підняття). Саме тому деякий код працює, навіть якщо звертається до змінної чи функції до рядка, де її, на перший погляд, оголошено. Але те, що саме підіймається — по-різному для var, let/const і function.
console.log(x); // undefined — не помилка!
var x = 5;
console.log(x); // 5Рушій фактично «бачить» код так, ніби оголошення var x підняте на початок області видимості, а привласнення x = 5 лишається на своєму місці:
var x; // підняте оголошення
console.log(x); // undefined
x = 5; // привласнення лишається тутМи бачили це в модулі «Функції»: на відміну від var, для function declaration підіймається не лише оголошення, а й усе тіло функції — тому її можна викликати до визначення в коді:
sayHi(); // "Привіт" — працює
function sayHi() {
console.log("Привіт");
}let і const теж технічно «підіймаються» — рушій знає про їхнє існування заздалегідь — але вони лишаються недоступними від початку блоку до рядка, де оголошені. Ця область називається тимчасовою мертвою зоною:
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 5;Різниця з var суттєва: var мовчки повертає undefined до ініціалізації, а let/const кидають явну помилку — це набагато безпечніше, бо помилка виявляється одразу, а не проявляється як загадковий undefined десь далі в коді.
Оскільки function expression і стрілкові функції зберігаються у змінній (const чи let), сама змінна підіймається за правилами let/const — доступна лише після рядка визначення:
sayHi(); // ReferenceError: Cannot access 'sayHi' before initialization
const sayHi = () => console.log("Привіт");Hoisting дозволяє розташовувати допоміжні function declaration нижче в файлі, після основної логіки, що часто читається зручніше — «спочатку головне, деталі — далі»:
function processOrder(order) {
validate(order);
return calculateTotal(order);
}
// Допоміжні функції визначені нижче — hoisting робить це можливим
function validate(order) { /* ... */ }
function calculateTotal(order) { /* ... */ }Покладання на hoisting var як на «звичайну» поведінку — сучасний код уникає var саме через цю неочевидну плутанину.
Очікування, що function expression поводиться як function declaration щодо виклику до визначення.
Плутанина ReferenceError із TDZ і звичайного ReferenceError через відсутню змінну — повідомлення про TDZ явно каже 'before initialization'.
Hoisting — не «магія», а результат того, що рушій реєструє оголошення до виконання коду. var піднімається з початковим значенням undefined, function declaration піднімається повністю разом із тілом, а let/const технічно теж піднімаються, але лишаються недоступними (тимчасова мертва зона) до рядка оголошення — це й робить let/const безпечнішими за var.
Спробуйте самостійно
Не запускаючи код, визначте, що виведе кожен рядок: console.log(a); var a = 1;, потім console.log(b); let b = 1;. Поясніть різницю своїми словами, а потім перевірте в консолі.