Что такое "hoisting" в JavaScript?
Hoisting (поднятие) — это механизм в JavaScript, при котором объявления переменных, функций и классов перемещаются в начало их области видимости перед выполнением кода.
Однако, при поднятии переменные остаются без инициализации, а классы и let
/const
-переменные находятся в "Temporal Dead Zone" (TDZ) до фактического объявления.
Hoisting переменных
var
Переменные, объявленные с var
, поднимаются, но не инициализируются. Их значение по умолчанию — undefined
:
console.log(a); // undefined
var a = 10;
console.log(a); // 10
Фактически код интерпретируется так:
var a; // Объявление поднято
console.log(a); // undefined
a = 10;
console.log(a); // 10
let
и const
Переменные, объявленные с let
и const
, также поднимаются, но не инициализируются, поэтому доступ к ним до объявления вызывает ReferenceError
:
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
То же самое с const
:
console.log(c); // ReferenceError
const c = 30;
Причина — временная зона TDZ (Temporal Dead Zone): переменная существует, но доступ к ней запрещен до явного объявления.
Hoisting функций
Function Declaration (объявление функции)
Функции, объявленные с function
, поднимаются вместе с их телом:
greet(); // "Hello, world!"
function greet() {
console.log("Hello, world!");
}
Так как function greet()
полностью поднимается, код работает.
Function Expression (функциональное выражение)
Функции, объявленные через var
, ведут себя как переменные:
console.log(sayHello); // undefined
var sayHello = function() {
console.log("Hello!");
};
sayHello(); // "Hello!"
Поднимается только объявление var sayHello;
, но не само присвоение.
Если использовать let
или const
, произойдет ReferenceError
:
console.log(sayHi); // ReferenceError
let sayHi = function() {
console.log("Hi!");
};
Hoisting классов
Классы в JavaScript поднимаются, но остаются в TDZ, как let
и const
:
const obj = new MyClass(); // ReferenceError
class MyClass {
constructor() {
this.name = "Class";
}
}
Причина в том, что классы в JS не поднимают свое определение.
Hoisting import
Модули ES6 импортируются до выполнения кода, что делает их доступными сразу:
import { myFunction } from './module.js';
myFunction(); // Можно использовать без проблем
Но импорты всегда должны быть в начале файла.
Итоговая таблица hoisting
Декларация | Доступ до объявления |
---|---|
var foo | undefined |
let foo | ReferenceError |
const foo | ReferenceError |
class Foo | ReferenceError |
var foo = function() { ... } | undefined |
function foo() { ... } | Работает нормально |
import | Работает нормально |