Hoisting: поднятие переменных и функций
Что такое Hoisting? 🏗️
Hoisting (поднятие) — это механизм JavaScript, который "поднимает" объявления переменных (var, let, const) и функций в начало их области видимости перед выполнением кода.
Но будь осторожен: поднимается только объявление, а не инициализация! Это может приводить к неожиданным результатам.
console.log(message); // undefined, а не ошибка!
var message = "Hello, hoisting!";
Как работает Hoisting? 🤔
1. С переменными var
Переменные, объявленные через var, поднимаются и инициализируются значением undefined.
console.log(name); // undefined (но не ReferenceError!)
var name = "Alice";
Фактически, интерпретатор видит это так:
var name; // Поднято вверх
console.log(name); // undefined
name = "Alice"; // Присваивание остаётся на месте
Важно:
letиconstтоже поднимаются НО не инициализируются (ReferenceError).varсоздаёт глобальную или функциональную область видимости, аlet/const— блочную.
2. С функциями
Function Declaration (объявление функции) поднимается целиком!
sayHi(); // "Hi!" — работает, даже если вызов перед объявлением!
function sayHi() {
console.log("Hi!");
}
Но Function Expression (функциональное выражение) — не поднимается!
sayHello(); // TypeError: sayHello is not a function
var sayHello = function() {
console.log("Hello!");
};
Здесь переменная sayHello поднята, но её значение (undefined) ещё не функция.
Hoisting в let и const 🚧
Переменные let и const недоступны до объявления (в отличие от var). Они находятся в "временной мёртвой зоне" (TDZ).
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10;
💡 Совет: Всегда объявляй переменные до использования (
let/const), чтобы избежать TDZ.
Как запомнить разницу? 🧠
Таблица: Hoisting в var, let, const и функциях
| Тип | Поднимается? | Инициализируется | Пример ошибки |
|---|---|---|---|
var |
✅ Да | undefined |
undefined |
let |
✅ (но TDZ) | ❌ Нет | ReferenceError |
const |
✅ (но TDZ) | ❌ Нет | ReferenceError |
| Function Declaration | ✅ Да | Вся функция | — |
| Function Expression | ❌ Нет | ❌ Нет | TypeError / ReferenceError |
Практика: типичные ловушки Hoisting 🎯
Пример 1: var в цикле
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Вывод: 3, 3, 3 (а не 0, 1, 2!)
Почему?
- var создаёт одну переменную на всю функцию/глобальную область.
- Решение: используй let (блочная область видимости).
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Вывод: 0, 1, 2 ✅
Пример 2: Переопределение функции
func(); // "Вторая"
function func() {
console.log("Первая");
}
function func() {
console.log("Вторая");
}
Почему?
- Function Declarations поднимаются, и последнее объявление побеждает.
Итоги: правила Hoisting 🏆
varподнимается cundefined.let/constподнимаются, но недоступны до объявления (TDZ).- Function Declaration поднимается целиком.
- Function Expression подчиняется правилам переменных (
var/let/const).
🔥 Совет от Данилы Бежина (из его YouTube-канала):
"Всегда используй
constпо умолчанию,let— если переменная меняется,var— никогда. Так код будет предсказуемым!"
Попробуй применить эти знания в своём коде — и увидишь, как легко избежать скрытых багов! 🚀