var, let и const — в чём разница? Block scope и TDZ

Почему var больше не пишут и что отвечать про block scope и TDZ.

Область видимости (scope) — часть кода, где переменная доступна. var видна во всей функции, let/const — только внутри блока {}.

Главные различия

Свойствоvarletconst
Область видимостифункцияблокблок
Переназначениедаданет
Повторное объявлениеданетнет
До объявленияundefinedошибка (TDZ)ошибка (TDZ)

Block scope: var «вытекает» из блока

var игнорирует фигурные скобки if и циклов — она привязана к функции. let и const ограничены блоком.

if (true) {
  var a = 1;
  let b = 2;
}
console.log(a);   // var видна снаружи блока

try {
  console.log(b); // let — нет
} catch (e) {
  console.log(e.name);
}

Вывод:

1
ReferenceError

TDZ — временная мёртвая зона

let и const тоже «поднимаются» (об этом — следующий урок), но обратиться к ним до строки объявления нельзя — это и есть TDZ. У var такого нет: до объявления она просто undefined.

console.log(x);  // var: уже существует, но без значения
var x = 5;

try {
  console.log(y); // let: ещё в TDZ
  let y = 10;
} catch (e) {
  console.log(e.name);
}

Вывод:

undefined
ReferenceError

const запрещает переназначение, но не мутацию

Важнейшая тонкость: const запрещает менять привязку переменной к значению. Если значение — объект, его внутренности менять можно.

const arr = [1, 2];
arr.push(3);        // мутация — можно
console.log(arr);

try {
  arr = [9];        // переназначение — нельзя
} catch (e) {
  console.log(e.name);
}

Вывод:

[ 1, 2, 3 ]
TypeError

Что отвечать про «какой выбрать»

Современная рекомендация, которую ждут на собеседовании: по умолчанию const, а let — только там, где переменную действительно нужно переназначать. var в новом коде не используют вовсе. Такой подход делает код предсказуемее: видя const, читатель сразу знает, что привязка не изменится. Если же спросят «а в чём именно опасность var?» — назовите две вещи: «утечку» из блока (переменная видна шире, чем ожидаешь) и тихий undefined при обращении до присваивания вместо явной ошибки.

Итог

  • var — функциональная область, «всплывает» как undefined; в новом коде не используется.
  • let/const — блочная область и TDZ: до объявления обращение даёт ошибку.
  • const запрещает переназначение, но не мутацию содержимого объекта/массива.
Проверьте себя
1. Чему равна область видимости переменной, объявленной через var внутри if?
AТолько блок if
BВся функция (или модуль/глобал)
CТолько строка объявления
Dvar нельзя объявить в if
2. Что произойдёт при обращении к let-переменной до её объявления?
AВернётся undefined
BВернётся null
CБудет ReferenceError (TDZ)
DПеременная создастся автоматически
3. Можно ли изменить массив, объявленный через const?
AНет, const делает массив полностью неизменяемым
BДа, можно мутировать (push), но нельзя переназначить переменную
CМожно только читать элементы
DТолько если массив пустой
Поддержать проект