Avatar ·

Чем отличаются let и var в JavaScript? Объясните на примерах

Привет! Я начал изучать JavaScript и столкнулся с путаницей. Я знаю, что раньше все объявляли переменные через `var`, а теперь в современных учебниках рекомендуют `let`. Вроде бы оба делают одно и то же — создают переменные. Но когда я пишу код, они ведут себя по-разному. Вот пример, который меня сбил с толку: ```javascript var x = 10; if (true) { var x = 20; // Я думал, это новая переменная console.log(x); // 20 } console.log(x); // 20 — почему не 10? ``` Если я заменю `var` на `let`: ```javascript let x = 10; if (true) { let x = 20; console.log(x); // 20 } console.log(x); // 10 — а тут 10, как и ожидалось ``` Почему так происходит? И ещё я слышал про "всплытие" (hoisting) — это тоже как-то связано? Объясните, пожалуйста, для новичка, когда использовать `let`, а когда `var`, и в чём ключевые отличия. Мне важно понять это, чтобы не допускать ошибок в будущем. <<>>

Главные отличия: область видимости, всплытие и повторное объявление

Разница между let и var — одна из самых частых тем для путаницы у новичков. Давайте разберём три ключевых отличия на конкретных примерах.

1. Область видимости (Scope)

var имеет функциональную область видимости, а let — блочную (ограничена фигурными скобками {}).

// var — виден за пределами блока
if (true) {
  var a = 1;
}
console.log(a); // 1 — переменная "утекла" из блока

// let — живёт только внутри блока
if (true) {
  let b = 2;
}
console.log(b); // ReferenceError: b is not defined

Именно поэтому в вашем первом примере var x = 20 перезаписал внешнюю переменную — у var нет блочной изоляции. let же создал новую переменную только внутри if.

2. Всплытие (Hoisting)

Обе конструкции "всплывают" (объявления перемещаются вверх своей области видимости), но ведут себя по-разному:

  • var — всплывает и инициализируется значением undefined
  • let — всплывает, но не инициализируется (находится в "временной мёртвой зоне")
console.log(x); // undefined — ошибки нет, но значение не определено
var x = 5;

console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 10;

Это защищает от случайного использования переменной до её объявления.

3. Повторное объявление

var позволяет переобъявлять одну и ту же переменную сколько угодно раз:

var name = "Alice";
var name = "Bob"; // работает, перезаписывает
console.log(name); // Bob

let запрещает повторное объявление в той же области видимости:

let name = "Alice";
let name = "Bob"; // SyntaxError: Identifier 'name' has already been declared

Это помогает избежать случайных перезаписей.

Когда что использовать?

  • Всегда используйте let (и const для неизменяемых значений) в современном коде. Это безопаснее и предсказуемее.
  • var оставьте только для поддержки очень старых браузеров (IE11 и ниже) или если вы пишете код, который должен работать в окружениях, не поддерживающих ES6.

В итоге: let — это улучшенная версия var с блочной областью видимости и защитой от ошибок. Современные стандарты кодирования (ESLint, Prettier) часто запрещают var по умолчанию.

<<>>

Практический совет: как отлавливать ошибки с var

Самая коварная проблема с var возникает в циклах и обработчиках событий. Рассмотрим классический пример:

// Проблема с var
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Выведет: 3, 3, 3 (а не 0, 1, 2)

Почему? Потому что var i имеет функциональную область видимости — после цикла i равна 3, и все колбэки видят одно и то же финальное значение.

Решение с let:

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Выведет: 0, 1, 2 — каждая итерация создаёт свою копию i

let в цикле создаёт новую переменную для каждой итерации, что решает проблему замыканий. Если вы работаете с легаси-кодом на var, приходится использовать немедленно вызываемые функции (IIFE) или .bind(). Но с let эта головная боль уходит полностью. Поэтому при изучении JS сразу привыкайте к let/const — это спасёт от множества багов.