12k
All articles

Объявление переменных в JavaScript: разбираемся с var, let и const

Сравнение var, let и const по области видимости в ES6, hoisting и Temporal Dead Zone позволяет писать JavaScript-код без ошибок с понятным намерением.

OpenReplay Team
OpenReplay Team
Объявление переменных в JavaScript: разбираемся с var, let и const

Современная разработка на JavaScript требует ясности в объявлении переменных JavaScript — однако многие разработчики до сих пор испытывают трудности с выбором между var, let и const. Понимание области видимости переменных ES6 — это не просто заучивание правил; это написание кода, который передаёт намерения и предотвращает ошибки до их возникновения.

Ключевые моменты

  • Блочная область видимости (let/const) обеспечивает лучшую изоляцию переменных, чем функциональная область видимости (var)
  • Временная мёртвая зона (Temporal Dead Zone) предотвращает использование переменных до их инициализации
  • const предотвращает переприсваивание, но не мутацию объектов и массивов
  • Современный JavaScript отдаёт предпочтение const по умолчанию, let при необходимости и избегает var

Понимание трёх ключевых слов объявления в JavaScript

JavaScript предлагает три способа объявления переменных, каждый из которых имеет свои особенности в отношении области видимости, поднятия (hoisting) и переприсваивания. Ваш выбор сигнализирует о разных намерениях как движку JavaScript, так и другим разработчикам, читающим ваш код.

Блочная область видимости против функциональной

Фундаментальное различие между современной областью видимости переменных ES6 и устаревшими паттернами заключается в том, как изолируются переменные:

function processData() {
    if (true) {
        var x = 1;  // Function-scoped
        let y = 2;  // Block-scoped
        const z = 3; // Block-scoped
    }
    console.log(x); // 1 (accessible)
    console.log(y); // ReferenceError
    console.log(z); // ReferenceError
}

С var переменные «вытекают» из блоков, но остаются внутри функций. И let, и const соблюдают границы блоков — любые фигурные скобки создают новую область видимости, включая те, что в циклах, условных конструкциях и обычных блоках.

Временная мёртвая зона: подробное объяснение

Объявления переменных JavaScript с let и const поднимаются (hoisted), но остаются неинициализированными до достижения их объявления. Это создаёт временную мёртвую зону (Temporal Dead Zone, TDZ):

console.log(myVar);   // undefined (hoisted, initialized)
console.log(myLet);   // ReferenceError (TDZ)
console.log(myConst); // ReferenceError (TDZ)

var myVar = 1;
let myLet = 2;
const myConst = 3;

TDZ предотвращает тонкие ошибки, которые часто вызывало поведение var. Вы не можете случайно использовать переменную до её правильной инициализации — движок немедленно выбросит ошибку.

Переприсваивание против мутации

Критическое различие, которое упускают многие разработчики: const предотвращает переприсваивание, а не мутацию:

const user = { name: 'Alice' };
user.name = 'Bob';          // Allowed (mutation)
user = { name: 'Charlie' }; // TypeError (reassignment)

const scores = [95, 87];
scores.push(91);            // Allowed
scores = [100, 100];        // TypeError

Для истинной неизменяемости комбинируйте const с Object.freeze() или библиотеками для работы с неизменяемыми данными. Само по себе ключевое слово объявления не делает ваши данные неизменяемыми — оно делает неизменяемой привязку (binding).

Современные лучшие практики объявления переменных

Кодовые базы JavaScript сегодня следуют чёткой иерархии:

  1. По умолчанию используйте const: применяйте для значений, которые не будут переприсваиваться. Это включает большинство переменных, даже объекты и массивы, которые вы будете мутировать.

  2. Используйте let для переприсваивания: счётчики циклов, переменные-аккумуляторы и значения, которые действительно требуют повторной привязки.

  3. Избегайте var в новом коде: не существует современного сценария использования, где var предоставляет преимущества перед let.

Современные инструменты обеспечивают соблюдение этих паттернов. Правила ESLint no-var и prefer-const автоматически отлавливают нарушения. TypeScript рассматривает правила области видимости переменных ES6 как фундаментальные, делая блочную область видимости ментальной моделью по умолчанию.

Особенности фреймворков

React-хуки зависят от предсказуемого поведения объявлений переменных JavaScript:

function Counter() {
    const [count, setCount] = useState(0); // const for the binding
    
    // Wrong: Can't reassign
    // count = count + 1;
    
    // Right: Use the setter
    setCount(count + 1);
}

Composition API во Vue и другие современные фреймворки следуют аналогичным паттернам, где доминирует const, потому что системы реактивности обрабатывают обновления через методы, а не через переприсваивание.

Почему устаревший код всё ещё использует var

Вы встретите var в старых кодовых базах по историческим причинам. До ES6 (2015) это был единственный вариант. Миграция требует тщательного тестирования, потому что:

  • Изменение var на let в циклах может исправить ошибки или внести их, в зависимости от поведения замыканий
  • Некоторый устаревший код намеренно эксплуатирует поднятие с функциональной областью видимости var
  • Старые инструменты сборки могут некорректно транспилировать область видимости переменных ES6

При рефакторинге используйте автоматизированные инструменты, такие как jscodeshift, с тщательным покрытием тестами. Не конвертируйте вручную тысячи объявлений — позвольте инструментам обработать механические изменения, пока вы проверяете поведение.

Заключение

Объявления переменных JavaScript в современном коде следуют простому правилу: используйте const по умолчанию, let когда нужно переприсваивание, и никогда var. Это не о следовании трендам — это о написании кода, который чётко выражает намерения и использует область видимости переменных ES6 для предотвращения целых категорий ошибок. Временная мёртвая зона, блочная область видимости и правила переприсваивания — это не препятствия, а ограждения, которые направляют вас к более поддерживаемому JavaScript.

Часто задаваемые вопросы

Могу ли я использовать const для массивов и объектов, если планирую изменять их содержимое?

Да, const предотвращает только переприсваивание самой переменной, а не изменение содержимого. Вы можете добавлять, удалять или изменять свойства в объектах и элементы в массивах, объявленных с const. Переменная всегда указывает на один и тот же объект или массив в памяти.

Что произойдёт, если я попытаюсь обратиться к переменной let или const до её объявления?

Вы получите ReferenceError из-за временной мёртвой зоны. В отличие от var, которая возвращает undefined при обращении до объявления, переменные let и const существуют в неинициализированном состоянии до тех пор, пока код не достигнет строки их объявления.

Стоит ли рефакторить все объявления var на let или const в существующем коде?

Только при тщательном тестировании. Хотя это обычно полезно, изменение var на let в циклах может изменить поведение замыканий. Используйте автоматизированные инструменты рефакторинга с комплексным покрытием тестами, а не ручные изменения, чтобы избежать внесения ошибок.

Open-source session replay

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.