Переменные: var, let, const — отличия и когда использовать
Разбираемся чем отличаются var, let и const в JavaScript. Область видимости, всплытие, переназначение — с примерами и частыми ошибками.
Зачем нужны переменные
Переменная — это именованная ячейка памяти. Вы кладёте туда данные, чтобы использовать их позже:
let userName = 'Алексей'
console.log(userName) // Алексей
В JavaScript есть три ключевых слова для объявления переменных: var, let и const. Если вы начинаете изучать язык — важно понять разницу между ними, потому что они ведут себя совершенно по-разному.
const — объявляйте по умолчанию
const создаёт переменную, значение которой нельзя переназначить:
const PI = 3.14
PI = 3 // TypeError: Assignment to constant variable
Но «нельзя переназначить» не значит «нельзя изменить». Если внутри объект или массив — вы можете менять его содержимое:
const user = { name: 'Аня', age: 25 }
user.age = 26 // OK, свойство поменяли
user.city = 'Мск' // OK, добавили свойство
const numbers = [1, 2, 3]
numbers.push(4) // OK
numbers[0] = 99 // OK
user = {} // TypeError — сама переменная не меняется
Отсюда правило: const не делает значение иммутабельным. Он запрещает присваивать новое значение самой переменной.
Когда использовать: всегда, пока точно не понадобится переназначать. Так код понятнее — читая const, вы сразу знаете, что значение не поменяется ниже по файлу.
let — когда нужно переназначить
let позволяет менять значение:
let score = 0
score = 10 // OK
score += 5 // OK, score = 15
Типичные случаи — счётчики, промежуточные результаты, значения которые обновляются в цикле:
let result = null
for (const item of items) {
if (item.active) {
result = item
break
}
}
var — устаревший способ
var — это то, как объявляли переменные до ES6 (до 2015 года). Работает, но имеет пару неприятных сюрпризов.
1. Всплытие (hoisting)
Объявления var всплывают в начало области видимости. Кажется, что переменная существует до того, как вы её объявили:
console.log(name) // undefined, а не ошибка
var name = 'Борис'
JavaScript видит это так:
var name // всплыло наверх, значение undefined
console.log(name) // undefined
name = 'Борис'
Сравните с let и const — при обращении до объявления будет ошибка:
console.log(age) // ReferenceError: Cannot access 'age' before initialization
let age = 30
Это полезное поведение. Лучше получить ошибку, чем молча работать с undefined.
2. Функциональная область видимости
var ограничен функцией, но не блоком. Блок — это всё между { }, например тело if, for, while.
if (true) {
var x = 10
}
console.log(x) // 10 — x «утекла» за пределы if
С let и const такого не случится — они блочные:
if (true) {
let y = 10
}
console.log(y) // ReferenceError: y is not defined
3. Классическая ошибка с циклом
Вот баг, который ловил каждый разработчик старой школы:
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100)
}
// Вывод: 3, 3, 3
Три тройки вместо 0, 1, 2. Потому что var — одна переменная на всю функцию. К моменту срабатывания таймеров цикл уже завершился, и i равно 3.
С let каждый шаг цикла создаёт свою копию i:
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100)
}
// Вывод: 0, 1, 2
4. Повторное объявление
var позволяет объявить одну и ту же переменную дважды — без предупреждения:
var x = 5
var x = 10 // OK, молча перезаписано
let и const так не дадут:
let y = 5
let y = 10 // SyntaxError: Identifier 'y' has already been declared
Сводная таблица отличий
| Свойство | var | let | const |
|---|---|---|---|
| Область видимости | функция | блок | блок |
| Всплытие (hoisting) | да, значение undefined | да, но «мёртвая зона» | да, но «мёртвая зона» |
| Можно переназначить | да | да | нет |
| Повторное объявление | да | нет | нет |
| Использовать в 2025 году | нет | да | да |
Что такое «мёртвая временная зона» (TDZ)
Между началом блока и строкой объявления let/const переменная находится в Temporal Dead Zone. Она существует, но обращаться к ней нельзя:
{
// здесь TDZ для name
console.log(name) // ReferenceError
let name = 'Оля' // здесь TDZ заканчивается
}
Это защита от случайного обращения к переменной до её инициализации.
Можно ли объявить переменную без ключевого слова?
Технически — да. Но так делать никогда не следует:
city = 'Москва' // глобальная переменная (в браузере → window.city)
В строгом режиме это вызовет ошибку:
'use strict'
city = 'Москва' // ReferenceError: city is not defined
Всегда используйте let, const или var.
Практические правила
- По умолчанию —
const. Если значение не нужно менять —const. Это 80% переменных в типичном коде. - Нужно переназначить —
let. Счётчики, аккумуляторы, промежуточные значения. var— не используйте. Он остался для обратной совместимости. В новом коде ему не место.
// Хороший стиль
const API_URL = 'https://api.example.com'
const MAX_RETRIES = 3
const users = ['Анна', 'Иван', 'Мария']
let currentUserIndex = 0
let hasError = false
for (let i = 0; i < users.length; i++) {
// ...
}
Частые вопросы
Можно ли использовать const для объектов и массивов? Да. То что вы не можете переназначить переменную не мешает менять содержимое. Для настоящей иммутабельности используйте Object.freeze() или Object.assign() / spread для создания копий.
Что если я не знаю, будет ли переменная меняться? Начните с const. Если дальше по коду понадобится переназначить — поменяйте на let.
Почему в старых туториалах везде var? Потому что let и const появились в ES6 (2015 год). Материалы старше этого возраста используют только var.