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

Почему видимость var выходит за пределы блока а let и const нет?

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

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

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

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

Почему видимость var выходит за пределы блока, а let и const нет?

Это различие связано с областью видимости (scope) и hoisting (поднятием). var использует функциональную область видимости, в то время как let и const используют блочную область видимости. Это фундаментальное различие в JavaScript, возникшее из-за эволюции языка.

Функциональная область видимости (var)

Переменная var имеет область видимости функции, а не блока. Это значит, что она видна во всей функции, независимо от того, где объявлена.

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

var не уважает границы if, for, while и других блоков кода. Для var имеет значение только границы функции.

Блочная область видимости (let и const)

Переменные let и const уважают блочную область видимости. Они видны только внутри блока {}, в котором объявлены.

function example() {
  if (true) {
    let y = 10;
    const z = 15;
  }
  console.log(y); // ReferenceError: y is not defined
  console.log(z); // ReferenceError: z is not defined
}

Историческая причина

JavaScript был создан в 1995 году, когда блочная область видимости считалась менее актуальной. var была единственным способом объявления переменных. В 2015 году (ES6) были введены let и const для решения проблем var.

Старый код полагался на функциональную область видимости var, поэтому разработчики языка не могли просто изменить поведение var — это сломало бы миллионы строк кода.

Hoisting (поднятие)

Это усугубляет ситуацию. Переменные var «поднимаются» (hoisting) в начало своей функции:

function hoistExample() {
  console.log(a); // undefined (не ошибка!)
  if (true) {
    var a = 5;
  }
  console.log(a); // 5
}

Это эквивалентно:

function hoistExample() {
  var a; // объявление поднято
  console.log(a); // undefined
  if (true) {
    a = 5; // присваивание остаётся на месте
  }
  console.log(a); // 5
}

Let и const тоже поднимаются, но находятся в «мёртвой зоне» (Temporal Dead Zone) до места объявления:

function hoistExample2() {
  console.log(b); // ReferenceError: Cannot access 'b' before initialization
  if (true) {
    let b = 10;
  }
}

Практические различия

Цикл с var:

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Выведет: 3, 3, 3
// Потому что переменная i поднята вверх и к моменту выполнения callbacks, i уже равна 3

Цикл с let:

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Выведет: 0, 1, 2
// Потому что каждая итерация создаёт новую область видимости с собственным i

Вложенные блоки

{
  var x = 1;
}
{
  let y = 2;
}

console.log(x); // 1 (видна за пределами первого блока)
console.log(y); // ReferenceError: y is not defined

Зачем это нужно было?

Блочная область видимости (let и const):

  • Предотвращает ошибки из-за случайного переиспользования переменных
  • Делает код более предсказуемым
  • Позволяет переиспользовать имена переменных в разных блоках
  • Упрощает написание чистого, безопасного кода

Современные практики

В современном JavaScript:

  • Никогда не используй var — это считается плохой практикой
  • Используй const по умолчанию — она неизменяема по ссылке
  • Используй let если переменная меняется — когда нужна мутируемая переменная
// Современный стиль
const user = { name: 'John' };
let count = 0;

if (true) {
  const message = 'Hello';
  let temp = 42;
  console.log(message, temp);
}

console.log(message); // ReferenceError
console.log(temp);    // ReferenceError

Вывод

var имеет функциональную область видимости из-за исторических причин и старого дизайна языка. let и const используют более логичную блочную область видимости, которая респектирует границы блоков кода. Это делает let и const безопаснее и более предсказуемыми в использовании.