Область видимости переменных в JavaScript: let, const, var и замыкания

JS / Основы

Область видимости переменных в JavaScript: let, const, var и замыкания

Глобальная, модульная, функциональная и блочная область видимости, временная мёртвая зона, замыкания и частые ошибки.

Опубликовано 04.09.2026 4 минуты чтения
Содержание статьи

Область видимости определяет, где идентификатор доступен в коде. Чем уже область переменной, тем меньше мест могут случайно изменить её значение и тем проще понимать программу.

В современном JavaScript по умолчанию используйте const, а let — когда привязку действительно нужно переназначить. var встречается в старом коде и отличается функциональной, а не блочной областью.

Глобальная и модульная область

Переменная классического скрипта верхнего уровня может стать частью глобального окружения. Это создаёт риск конфликтов между файлами.

ES-модуль имеет собственную верхнеуровневую область:

HTML
<script type="module" src="main.js"></script>​

JavaScript
// main.jsconst applicationName = 'Code4web';​console.log(window.applicationName); // undefined​

Экспортируйте только то, что нужно другим модулям:

JavaScript
export function formatDate(date) {  return new Intl.DateTimeFormat('ru-RU').format(date);}​

Функциональная область

Параметры и объявления внутри функции недоступны снаружи:

JavaScript
function calculateTotal(price, quantity) {  const total = price * quantity;  return total;}​console.log(calculateTotal(500, 3)); // 1500console.log(total); // ReferenceError​

Каждый вызов получает собственные параметры и локальные значения.

Блочная область let и const

Блок создаётся фигурными скобками у if, for, while или просто {}:

JavaScript
if (user.isAdmin) {  const message = 'Доступ разрешён';  console.log(message);}​console.log(message); // ReferenceError​

Переменная цикла тоже ограничена блоком:

JavaScript
for (let index = 0; index < 3; index += 1) {  console.log(index);}​console.log(index); // ReferenceError​

Это защищает вспомогательные значения от утечки в соседний код.

Чем отличается var

var игнорирует обычный блок и ограничивается функцией:

JavaScript
function example() {  if (true) {    var result = 42;  }​  console.log(result); // 42}​

Кроме того, объявление var поднимается и до строки инициализации имеет значение undefined:

JavaScript
console.log(value); // undefinedvar value = 10;​

Это не значит, что присваивание переместилось вверх. Движок обрабатывает примерно такую структуру:

JavaScript
var value;console.log(value);value = 10;​

В новом коде let и const делают ошибку заметнее.

Временная мёртвая зона

Объявления let и const тоже известны движку с начала блока, но недоступны до строки инициализации:

JavaScript
console.log(theme); // ReferenceErrorconst theme = 'dark';​

Период от начала блока до объявления называют temporal dead zone. Он предотвращает чтение переменной до получения осмысленного значения.

const не делает объект неизменяемым

const запрещает переназначить привязку:

JavaScript
const settings = { theme: 'light' };​settings.theme = 'dark'; // Допустимо.settings = {}; // TypeError.​

Если нужна поверхностная защита объекта, есть Object.freeze(), но вложенные объекты он автоматически не замораживает.

Лексическая область и замыкания

Внутренняя функция видит переменные места, где была создана, даже после завершения внешнего вызова:

JavaScript
function createCounter(initialValue = 0) {  let value = initialValue;​  return function increment() {    value += 1;    return value;  };}​const counter = createCounter(10);​console.log(counter()); // 11console.log(counter()); // 12​

Связь функции с окружающей лексической областью называется замыканием. Значение value остаётся приватным для возвращённой функции.

Замыкание в цикле

let создаёт отдельную привязку для каждой итерации:

JavaScript
const buttons = document.querySelectorAll('[data-index]');​for (let index = 0; index < buttons.length; index += 1) {  buttons[index].addEventListener('click', () => {    console.log(index);  });}​

С var все обработчики увидели бы итоговое значение общего index. Ещё яснее перебирать элементы напрямую:

JavaScript
for (const [index, button] of [...buttons].entries()) {  button.addEventListener('click', () => console.log(index));}​

Затенение переменных

Внутренняя переменная может иметь то же имя:

JavaScript
const status = 'global';​function showStatus() {  const status = 'local';  console.log(status);}​

Это допустимо, но частое затенение усложняет чтение. Используйте имена, отражающие роль: requestStatus, accountStatus.

Практические правила

  • подключайте проектный код как ES-модули;
  • объявляйте значение как можно ближе к месту использования;
  • выбирайте const, если переназначение не требуется;
  • используйте let для счётчиков и изменяемого состояния;
  • не создавайте неявные глобальные переменные;
  • избегайте var в новом коде;
  • не храните большое состояние в замыкании без необходимости — оно остаётся в памяти, пока доступна функция.

Что запомнить

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

Сообщить об ошибке в статье

Рекомендации редакции

Другие публикации из этого раздела.

Новые материалы

Получайте практические разборы без информационного шума

Одна общая рассылка о новых статьях и инструментах. Адрес будет активироваться только после подтверждения.

Подписка появится после подключения сервиса рассылок и Yandex SmartCaptcha.