← Назад к вопросам

Как работает Hoisting относительно var?

1.0 Junior🔥 281 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Hoisting и переменные var

Hoisting — один из самых неинтуитивных механизмов JavaScript. Это поведение, при котором объявления переменных и функций как будто бы "поднимаются" в начало области видимости (scope) перед выполнением кода.

Как работает Hoisting с var

Когда интерпретатор JavaScript обрабатывает код, он проходит в две фазы:

Фаза 1: Создание контекста выполнения (Creation Phase)

  • Все объявления var и функции скannируются
  • Переменные var инициализируются со значением undefined
  • Функции полностью поднимаются (и объявление, и тело)

Фаза 2: Выполнение (Execution Phase)

  • Код выполняется строка за строй
  • При встрече с назначением переменная получает реальное значение

Примеры Hoisting с var

Пример 1: Базовый hoisting

console.log(x); // undefined (не ошибка!)
var x = 5;
console.log(x); // 5

// Это воспринимается интерпретатором как:
var x;              // объявление поднимается
console.log(x);     // undefined
x = 5;              // присваивание остаётся на месте
console.log(x);     // 5

Пример 2: Hoisting функций

console.log(sayHi()); // "Привет!" — функция работает!

function sayHi() {
  return "Привет!";
}

// Функция полностью поднимается:
function sayHi() {
  return "Привет!";
}
console.log(sayHi()); // "Привет!"

Пример 3: Переменная vs функция

console.log(typeof name); // undefined (переменная)
console.log(typeof func);  // function (функция)

var name = "Алиса";
function func() {}

// Интерпретатор видит это как:
var name;              // поднялась, значение undefined
function func() {}     // функция полностью поднялась

console.log(typeof name); // undefined
console.log(typeof func);  // function

Пример 4: Hoisting в функциях

function example() {
  console.log(y); // undefined
  
  if (true) {
    var y = 10;
  }
  
  console.log(y); // 10 — y видна за пределами блока if!
}

// Это работает, потому что var имеет function scope, а не block scope:
function example() {
  var y;           // поднялась в начало функции
  console.log(y);  // undefined
  
  if (true) {
    y = 10;
  }
  
  console.log(y);  // 10
}

Отличие var от let и const

с let и const — Temporal Dead Zone (TDZ)

console.log(x); // ReferenceError: Cannot access x before initialization
let x = 5;

// let и const тоже поднимаются, но в Temporal Dead Zone
// Они недоступны от начала блока до строки объявления

Визуально:

// var — поднимается И инициализируется
var a;
console.log(a); // undefined ✓
a = 5;

// let/const — поднимаются, но НЕ инициализируются (TDZ)
// console.log(b); // ❌ ReferenceError
let b = 5;
console.log(b); // 5 ✓

Практические проблемы Hoisting

Проблема 1: Случайное переиспользование переменной

function process(items) {
  var result = [];
  
  for (var i = 0; i < items.length; i++) {
    // вложенный цикл
    for (var i = 0; i < 10; i++) { // ⚠️ ТА ЖЕ ПЕРЕМЕННАЯ i!
      result.push(items[i]);
    }
  }
  
  return result; // внешний i перезаписан
}

// Решение — использовать let
function process(items) {
  const result = [];
  
  for (let i = 0; i < items.length; i++) {
    for (let i = 0; i < 10; i++) { // разные i
      result.push(items[i]);
    }
  }
  
  return result; // работает правильно
}

Проблема 2: Confusion с function scope

if (true) {
  var x = 5;
}

console.log(x); // 5 — не undefined!

// let/const решают это:
if (true) {
  let y = 5;
}

console.log(y); // ReferenceError — y не видна снаружи

Почему это важно знать

  1. Отладка: Понимание hoisting помогает объяснить странные ошибки
  2. Миграция кода: При переходе с var на let/const поведение меняется
  3. Code review: Нужно замечать потенциальные конфликты
  4. Интервью: Это classic question для проверки понимания JavaScript

Резюме

  • var объявления поднимаются и инициализируются undefined
  • Присваивания остаются на месте
  • var имеет function scope (не block scope)
  • let и const поднимаются но не инициализируются (Temporal Dead Zone)
  • В современном коде используй let и const, избегай var