В чём разница между var, let и const? Что такое всплытие (hoisting)?
Короткий ответ
- var имеет функциональную область видимости, let и const — блочную
- Объявления var всплывают со значением undefined
- let и const до строки объявления находятся в TDZ
- Обращение к ним до объявления даёт ReferenceError
- const запрещает переприсваивание, но не мутацию объекта
- var создаёт свойство глобального объекта, let и const — нет
- В современном коде var практически не используют
let и const дают блочную область видимости и временную мёртвую зону, а var — устаревший механизм с функциональной областью и всплытием значения undefined.
Как сказать вслух
пример ответаvar виден во всей функции и до объявления равен undefined, из-за этого легко получить тихую ошибку. let и const видны только внутри блока, а до строки объявления обращаться к ним нельзя — будет исключение. const дополнительно запрещает присваивать переменной новое значение, хотя сам объект внутри менять можно. На практике я использую const по умолчанию и let, когда значение действительно меняется.
Подробный ответ
Основной ответ
Всплытие — это то, что движок при разборе кода регистрирует объявления до выполнения. Переменные var поднимаются в начало функции и сразу инициализируются значением undefined, поэтому обращение до объявления не падает, а молча возвращает undefined. let и const тоже регистрируются заранее, но не инициализируются: участок от начала блока до строки объявления называется временной мёртвой зоной (TDZ), и чтение там бросает ReferenceError. Область видимости var — функция целиком, let и const — ближайший блок в фигурных скобках, включая тело цикла: каждая итерация for с let получает свою привязку переменной, что решает классическую проблему замыканий в циклах. const фиксирует привязку, но не делает объект иммутабельным.
Ключевые моменты
- Блочная область. let и const живут внутри ближайших фигурных скобок, var — внутри всей функции.
- TDZ. До строки объявления let и const недоступны — это защита от использования неинициализированных переменных.
- const и мутации. const запрещает только переприсваивание; свойства объекта и элементы массива менять можно, для заморозки есть Object.freeze.
- let в циклах. Каждая итерация for с let создаёт отдельную переменную, поэтому колбэки в цикле видят правильное значение.
Практический контекст
Вопрос базовый, но по нему судят о понимании модели выполнения. Часто дают цикл с setTimeout и просят объяснить, почему с var выводится одно и то же число, а с let — разные. В рабочем коде это проявляется в линтерах (no-var, prefer-const) и в ревью: const по умолчанию делает код предсказуемее и сразу показывает читателю, что значение не переназначается.
Частые ошибки
- Утверждают, что const делает объект неизменяемым
- Говорят «let и const не всплывают» — всплывают, но без инициализации, отсюда TDZ
- Не могут объяснить поведение var в цикле с асинхронным колбэком