Как объявлять переменные в JavaScript: var, let и const

Что вы получите из этой статьи
- Понимание области видимости (scope) и блока (block) в контексте объявлений переменных.
- Разницу между var, let и const с рабочими примерами.
- Практические рекомендации, когда использовать каждое ключевое слово.
- Дополнительные модели мышления, проверочные списки и тест-кейсы для кода.
Работа с переменными — одно из первых умений, которые осваивает JavaScript-разработчик. Поскольку JavaScript широко применяется в веб-разработке, важно заложить прочную базу: правильно объявлять переменные и понимать их поведение.
Объявлять переменные в JavaScript легко, но нюансы зависят от ключевых слов: var, let и const. Каждое даёт своё поведение. Знание всех трёх вариантов помогает принимать верные архитектурные и прикладные решения.
Три способа объявить переменную в JavaScript
Есть три ключевых слова для объявления переменной:
- var
- let
- const
Ниже — подробное объяснение и примеры. Оригинальные примеры кода сохранены, а после них — расширенные пояснения и дополнительные примеры, которые полезно запустить в консоли.
Основные термины
Область видимости
Область видимости переменной (scope) — это часть программы, где переменная доступна. Переменные с глобальной областью видимости доступны во всём приложении. Ошибки в отслеживании scope часто приводят к багам по мере роста кода.
Блок
Функции, циклы и другие конструкции с фигурными скобками образуют блоки. Код внутри { } — это блок. Блоки можно вкладывать, и поведение переменных внутри блоков — ключ к пониманию let и const.
function blockTest(){
//This is a block
{
//This is a nested block
}
};Теперь применим эти понятия к каждому ключевому слову.
1. var
Переменная, объявленная через var, имеет область видимости:
- если объявлена внутри функции — видима в этой функции (функциональная область видимости);
- если объявлена вне функции — глобальная.
Пример:
var test = 5; //Variable declaration
function varTest(){
console.log(test); //This prints the variable
};
varTest();
>> 5
В этом примере переменная test объявлена вне функции и потому доступна внутри неё. Если внутри функции объявить переменную с тем же именем с помощью var, она переопределит значение для всей функции (поскольку var не уважает блочную границу внутри функции).
var test = 5;
function varTest(){
var test = 10;
console.log(test);
};
varTest();
>> 10
Если вывести значение вне вызова функции, вернётся глобальное значение:
console.log(test);
>> 5
Важно: var подвергается hoisting — объявление переменной поднимается вверх функции, но присвоение остаётся на месте. Это иногда вызывает неожиданные undefined-значения.
Пример hoisting:
function hoist(){
console.log(a); // undefined, объявление поднято, присвоение ещё не выполнено
var a = 1;
}
hoist();2. let
let даёт блочную область видимости: переменная видна только в том блоке, где объявлена.
Рассмотрим разницу с var на примере с вложенными блоками:
function varTest(){
var test = 5;
{
var test = 10;
console.log(test);
}
console.log(test);
};varTest();
>> 10
>> 10Оба вывода — 10, потому что var внутри блока перезаписал переменную функции.
Теперь пример с let:
function letTest(){
let test = 5;
{
let test = 10;
console.log(test);
}
console.log(test);
};letTest();
>> 10
>> 5let вводит новый локальный в блоке идентификатор. Это предотвращает непреднамеренные перезаписи переменных, особенно в больших функциях и циклах.
Дополнительно: let также подвержен hoisting, но в отличии от var он находится в “temporal dead zone” (TDZ) до места объявления — попытка обратиться до объявления вызовет ReferenceError.
Пример TDZ:
console.log(x); // ReferenceError
let x = 2;3. const
const похож на let по области видимости: блочный scope. Главное отличие — запрет на переназначение переменной после объявления.
const permanent = 10;Если попытаться объявить ту же переменную снова или переназначить её, вы получите синтаксическую ошибку:
const permanent = 20;
>> Uncaught SyntaxError: Identifier 'permanent' has already been declaredВажно понимать тонкость: const защищает привязку идентификатора к значению, но не делает само значение неизменяемым, если это объект или массив. То есть вы не сможете переназначить переменную, но сможете изменять поля объекта или элементы массива.
Пример:
const obj = { a: 1 };
obj.a = 2; // разрешено — меняется содержимое объекта
// obj = {}; // запрещено — попытка переназначить ссылкуПоведение в глобальной области и на уровне window (в браузере)
- var, объявленный в глобальной области, создаёт свойство на глобальном объекте (window в браузере).
- let и const не создают свойство на глобальном объекте.
Пример:
var g = 1;
let l = 2;
console.log(window.g); // 1
console.log(window.l); // undefinedПрактические рекомендации
- Используйте const по умолчанию для переменных, которые не должны переназначаться (ссылки на объекты, константы конфигурации).
- Используйте let, если вы ожидаете переназначение внутри блока (например, счётчик в цикле, временные переменные).
- Избегайте var в новом коде: только для совместимости или при осознанной необходимости функциональной области видимости.
Важно: предпочтение const + явные мутации объектов (через методы) делает код предсказуемее.
Когда выбор может давать сбой или быть недостаточным
- var может привести к трудноуловимым багам из-за поднятия и непреднамеренной перезаписи.
- const не защитит от изменения внутренней структуры объектов — для глубокой неизменяемости нужны дополнительные подходы: Object.freeze, иммутабельные структуры, библиотеки (immer).
- let и const в старых окружениях (старые браузеры) требуют транспиляции (например, Babel) или использования полифиллов для совместимости.
Альтернативные подходы
- Использовать TypeScript: строгая типизация помогает избегать ошибок и делает intent (намерение) явным.
- Функциональный стиль и иммутабельность: минимизировать мутацию объектов и применять чистые функции.
- Линтеры (ESLint) с правилом no-var и prefer-const помогут автоматизировать лучшие практики.
Модель мышления (heuristics)
- «Сначала const»: объявляйте переменные как const, затем меняйте на let только если нужно переназначение.
- Считайте let как локальную переменную для блока, var — для функции.
- const означает: “это имя всегда будет указывать на ту же ссылку”.
Критерии приёмки
- В коде нет использования var, если только это не вынуждено требованием среды.
- Все неизменяемые привязки объявлены через const.
- Переменные, используемые только в блоке, объявлены через let.
- Покрыты тесты, подтверждающие ожидаемую область видимости и поведение при переопределении.
Тест-кейсы и сценарии для проверки
- Hoisting для var
- Ожидается: console.log до объявления возвращает undefined.
- TDZ для let/const
- Ожидается: доступ до объявления для let/const вызывает ReferenceError.
- Переназначение const
- Ожидается: попытка переназначить идентификатор вызывает ошибку.
- Мутабельность объекта через const
- Ожидается: изменение поля объекта const допускается.
- Глобальное привязывание
- Ожидается: var создаёт свойство on window, let/const — нет.
Чеклист для ролей
- Разработчик
- Использует const по умолчанию.
- Применяет let для счётчиков и временных переменных.
- Избегает глобальных переменных.
- Code Reviewer
- Проверяет отсутствие var без причин.
- Убеждается, что const используется для намеренных констант.
- Смотрит на потенциальные мутации объектов.
- Архитектор
- Устанавливает правила ESLint: no-var, prefer-const.
- Поддерживает стандарты кодирования для команды.
Быстрый метод выбора (decision flowchart)
flowchart TD
A[Нужно объявить переменную?] --> B{Будет ли значение переназначаться?}
B -- Да --> C[Используйте let]
B -- Нет --> D{Это примитив или ссылка, которая не должна меняться?}
D -- Да --> E[Используйте const]
D -- Нет --> E
C --> F[Проверьте блоковую область видимости]
E --> F
F --> G[Добавьте тесты и линтер]Короткий словарь
- Scope — область видимости переменной.
- Block — код в фигурных скобках { }.
- Hoisting — процесс подъёма объявлений в начало области видимости.
- TDZ — временная зона до объявления, в которой let/const недоступны.
Примеры-«уловки», распространённые ошибки
- var в цикле for приводит к замыканию одной и той же переменной для всех итераций. Решение: используйте let в заголовке цикла.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // 3, 3, 3
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0); // 0, 1, 2
}- Попытка использовать const как “глубокую константу”. Для глубокой неизменяемости используйте Object.freeze и/или иммутабельные структуры.
Риски и смягчения
- Риск: случайная перезапись глобальных переменных. Смягчение: модульная архитектура, плотно настроенный линтер, избегание var.
- Риск: пропущенная мутация объектов, объявленных как const. Смягчение: код-ревью и правила по использованию иммутабельных структур.
Конечный вывод
var, let и const решают разные задачи. var исторически существовал в языке и даёт функциональную область видимости и подверженность hoisting. let и const появились в ES6, чтобы дать блочную область видимости и сделать намерения разработчика яснее: let для изменяемых привязок внутри блока, const — для привязок, которые не должны переназначаться. В современной разработке рекомендуют писать код в стиле “const по умолчанию, let при необходимости, var избегать”.
Спасибо за чтение. Попробуйте изменить примеры в реальной консоли браузера или Node.js: это лучший способ закрепить поведение при объявлении переменных.
Краткое резюме
- var: функциональная область видимости, hoisting, избегать в новом коде.
- let: блочная область видимости, можно переназначать, TDZ до объявления.
- const: блочная область видимости, нельзя переназначать, но объект/массив остаётся мутируемым.
Важно: используйте линтер и тесты — они защитят от большинства ошибок, связанных с неправильным выбором способа объявления переменной.