Hoisting: поднятие объявлений
Hoisting — поведение JavaScript-движка, при котором объявления переменных и функций «поднимаются» в начало своей области видимости до выполнения кода.
Зачем нужно
Hoisting объясняет, почему можно вызвать функцию до её объявления в коде, и почему обращение к переменной var до присвоения возвращает undefined, а не ошибку. Знание этого механизма помогает избегать неочевидных багов и понимать разницу между var, let, const и объявлениями функций.
Где используется
- Отладка неочевидного поведения кода с
var - Понимание порядка инициализации в модулях
- Объяснение Temporal Dead Zone для
let/const - Написание кода без зависимости от порядка объявлений
Основной контент
Поднятие function declaration
// Можно вызвать до объявления — весь код функции поднимается
sayHello; // 'Привет' — работает!
function sayHello() {
console.log('Привет');
}
// Function expression — НЕ поднимается
// greet; // TypeError: greet is not a function
const greet = function {
console.log('Привет');
};
Поднятие var
// var объявление поднимается, но не инициализация
console.log(x); // undefined (не ReferenceError!)
var x = 5;
console.log(x); // 5
// Эквивалентно такому коду:
var x; // поднято
console.log(x); // undefined
x = 5;
console.log(x); // 5
Temporal Dead Zone (TDZ) для let и const
// let и const тоже поднимаются, но НЕ инициализируются
// Обращение до объявления — ReferenceError
// console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 10;
// Temporal Dead Zone — промежуток от начала блока до let/const
{
// TDZ начинается здесь
// console.log(z); // ReferenceError
let z = 20; // TDZ заканчивается
console.log(z); // 20
}
var в циклах
// var имеет функциональную область — один i для всех итераций
for (var i = 0; i < 3; i++) {
setTimeout( => console.log(i), 0);
}
// Выводит: 3, 3, 3
// let создаёт новую переменную для каждой итерации
for (let j = 0; j < 3; j++) {
setTimeout( => console.log(j), 0);
}
// Выводит: 0, 1, 2
Порядок поднятия
// Порядок: function declarations > переменные
var x = 1;
function x() {} // function declaration поднимается выше var
// После поднятия x = 1 (переменная перезаписывает функцию при инициализации)
console.log(typeof x); // 'number'
Частые ошибки
- Использование переменной
varдо присвоения — получаемundefined, а не значение. Переходите наlet/const. - Ожидание поднятия
const/let— TDZ вызываетReferenceError. Объявляйте переменные в начале блока. - Function expression ≠ function declaration — стрелочные функции и функции в
constне поднимаются полностью.
Связанные темы
Ресурсы
⚡ Источник: ⎡spec03⎦ Hoisting согласно официальной спецификации · AsForJS
- 📅 2023-11-19 · YouTube
- Тезисы:
- Термина "hoisting" / "всплытие" в спецификации ECMAScript НЕТ — это жаргон из учебников
- В спецификации есть
Hoistable Declaration, но он описывает совсем не то, что подразумевают под "всплытием" - Реальный механизм: 3 фазы выполнения (parsing → instantiation → execution). На фазе instantiation создаются bindings, var связывается с
undefined, let/const остаются неинициализированными (hole) - Идентификатор всегда
Reference— отсюдаReferenceErrorдля любых проблем - Function declaration реально доступна сверху — это специальное правило спеки, а не "всплытие"
- Цитата: «Я беру на себя ответственность за каждое сказанное слово. Все декларируемое строго соответствует спецификации»
⚡ Источник: JavaScript and the Lexical Environment · AsForJS
- 📅 2023-05-12 · YouTube
- Тезисы: Lexical Environment — это запись Identifier→Binding на момент выполнения. То, что называют "hoisting", — это фаза
HoistableDeclarationпри создании Environment Record