Что такое hoisting (поднятие)?

Почему функцию можно вызвать выше её объявления, а переменная при этом undefined.

Hoisting (поднятие) — поведение, при котором объявления переменных и функций как будто «поднимаются» в начало своей области видимости ещё до выполнения кода.

Как это работает

Движок JavaScript обрабатывает код в два прохода. Сначала он «регистрирует» все объявления (создаёт переменные и функции), и только потом выполняет код сверху вниз. Поэтому имена уже существуют к моменту запуска — но значения присваиваются позже.

Функции поднимаются целиком

Function declaration (function foo() {}) поднимается полностью, вместе с телом. Поэтому её можно вызвать выше объявления.

console.log(sum(2, 3)); // работает до объявления!

function sum(a, b) {
  return a + b;
}

Вывод:

5

var поднимается без значения

var поднимается, но присваивание остаётся на месте. До строки с присваиванием переменная равна undefined — не ошибка, но и не значение.

console.log(name); // существует, но ещё пустая
var name = "Аня";
console.log(name);

Вывод:

undefined
Аня

Function expression НЕ поднимается как функция

Если функцию присвоить переменной, поднимется только переменная (как var/let), а не функция. Вызвать её до строки присваивания нельзя.

try {
  greet();
} catch (e) {
  console.log(e.name + ": greet ещё не функция");
}

var greet = function () {
  return "Привет";
};

console.log(greet());

Вывод:

TypeError: greet ещё не функция
Привет

До присваивания greet равна undefined, а вызов undefined() даёт TypeError.

Памятка по поднятию

Что объявленоПоднимается?Доступ до объявления
function declarationда, с теломработает
varда, без значенияundefined
let / constда, но в TDZReferenceError
function expressionкак переменнаяundefined / ошибка вызова

Зачем вообще знать про hoisting

На собеседовании за этим вопросом обычно стоит не желание услышать определение, а проверка: понимаете ли вы, почему один и тот же приём (function vs const fn = () => ...) ведёт себя по-разному. Практический вывод, который стоит озвучить: function declaration удобна, когда хочется свободно располагать функции в файле; стрелочные функции в const заставляют объявлять до использования, что делает поток данных линейным и читаемым. А var-поднятие — частый источник багов вроде «переменная внезапно undefined», поэтому переход на let/const с их TDZ как раз превращает такую ошибку в явный ReferenceError.

Итог

  • Hoisting — это «двухпроходная» обработка: сначала объявления, потом выполнение.
  • Function declaration поднимается целиком и доступна выше объявления.
  • var поднимается как undefined; function expression вызвать заранее нельзя.
Проверьте себя
1. Что выведет код: console.log(x); var x = 10;?
A10
Bundefined
CReferenceError
Dnull
2. Можно ли вызвать function declaration выше её объявления?
AНет, всегда ошибка
BДа, function declaration поднимается целиком с телом
CТолько если она без аргументов
DТолько в строгом режиме
3. Почему вызов function expression до присваивания даёт TypeError, а не ReferenceError?
AПеременная не существует
BПеременная поднята как undefined, а вызов undefined() — TypeError
CЭто всегда ReferenceError
DFunction expression нельзя присвоить var
Поддержать проект