Різниця між let, const і var
let і const відрізняються від var блочною областю видимості, забороною повторного оголошення та Temporal Dead Zone замість тихого undefined. Додатково const забороняє перезапис значення, а let і const, на відміну від var, не додають властивість до глобального об'єкта в браузері.
Теорія
TL;DR
var, функціональна або глобальна область видимості;letіconst, блочна.- Усі три піднімаються, але
varініціалізується якundefined, аletіconstлежать у TDZ і кидаютьReferenceError. - Повторне оголошення дозволене лише для
var; дляletіconstцеSyntaxError. - Перезаписати значення можна у
varіlet;constдаєTypeError. constзахищає посилання, а не вміст: властивості об'єкта чи елементи масиву змінювати можна.- У браузері
varна верхньому рівні стає властивістюwindow,letіconst, ні.
Швидкий приклад
function demo() {
if (true) {
var scopedToFunction = 'var';
let scopedToBlock = 'let';
const alsoScopedToBlock = 'const';
}
console.log(scopedToFunction); // 'var', visible in the whole function
console.log(scopedToBlock); // ReferenceError
console.log(alsoScopedToBlock); // ReferenceError
}
demo();Основні відмінності
| Критерій | var | let | const |
|---|---|---|---|
| Область видимості | Функція або глобальна | Блочна ({ ... }) | Блочна ({ ... }) |
| Підйом (hoisting) | Піднімається й ініціалізується як undefined | Піднімається, але не ініціалізується (помилка при зверненні до оголошення) | Піднімається, але не ініціалізується (помилка при зверненні до оголошення) |
| Повторне оголошення | Дозволене в одній області | Помилка | Помилка |
| Перезапис значення | Можна | Можна | Не можна |
| Додавання до об'єкта window (у браузері) | Так (window.varName) | Ні | Ні |
Область видимості
var, функціональна область видимості. Блок if, for чи просто { ... } для нього не бар'єр: змінна належить найближчій функції або глобальній області.
if (true) {
var a = 10;
}
console.log(a); // 10 (доступна за межами блока)let і const, блочна область видимості. Вони існують лише всередині тих фігурних дужок, у яких оголошені.
if (true) {
let b = 20;
const c = 30;
}
console.log(b); // ReferenceError
console.log(c); // ReferenceError
letіconst«живуть» тільки всередині блока{}.
Саме тому в циклі for із let кожна ітерація отримує власну змінну, а з var, одну спільну на весь цикл:
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i)); // 3, 3, 3
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j)); // 0, 1, 2
}Hoisting і Temporal Dead Zone
Усі змінні «піднімаються» на початок своєї області видимості, але по-різному. var одразу ініціалізується значенням undefined, а let і const потрапляють у Temporal Dead Zone (TDZ), тимчасову мертву зону, де змінна вже існує, але звертатися до неї ще не можна.
console.log(a); // undefined (var піднімається й ініціалізується)
var a = 5;
console.log(b); // ReferenceError (b у TDZ)
let b = 10;
console.log(c); // ReferenceError (c у TDZ)
const c = 15;TDZ, це не вада, а захист: замість тихого undefined, яке проявиться десь далі як дивний баг, ви отримуєте помилку саме в тому рядку, де припустилися помилки.
Повторне оголошення, перезапис і const з об'єктами
Повторно оголосити змінну в тій самій області можна тільки через var. Перезаписати значення можна у var і let, але не в const.
var x = 1;
var x = 2; // дозволено
console.log(x); // 2
let y = 1;
let y = 2; // SyntaxError: Identifier 'y' has already been declared
const z = 1;
z = 2; // TypeError: Assignment to constant variableВажливий нюанс: const захищає посилання, а не вміст. Об'єкт або масив, на який вказує константа, залишається змінним.
const user = { name: 'Tim' };
user.name = 'Alex'; // можна змінити властивість
console.log(user.name); // 'Alex'
user = {}; // TypeError: не можна перепризначити сам об'єктЯкщо потрібна справжня незмінність вмісту, використовують Object.freeze(user).
Глобальний об'єкт і правило вибору
У браузері var на верхньому рівні створює властивість глобального об'єкта, а let і const, ні.
var x = 10;
let y = 20;
const z = 30;
console.log(window.x); // 10
console.log(window.y); // undefined
console.log(window.z); // undefinedvar додає змінну до глобального об'єкта (window, globalThis), через що легко випадково перезаписати чужу глобальну змінну. let і const цього не роблять, тому код стає безпечнішим.
| Ситуація | Що використовувати | Чому |
|---|---|---|
| Змінна має змінюватися | let | Безпечніше за var, блочна область видимості |
| Змінна не має змінюватися | const | Явно показує незмінність |
| Старий код (до ES6) | var | Застаріло, лише для підтримки старих проєктів |
Просте правило запам'ятовування:
const, за замовчуванням.let, якщо потрібно змінити значення.var, ніколи в сучасному коді.
Типові помилки
- Думати, що
constробить об'єкт незмінним. Незмінним є лише прив'язка імені до значення; поля об'єкта й елементи масиву спокійно змінюються. - Вважати, що
letіconstне піднімаються. Вони піднімаються, просто до рядка оголошення перебувають у TDZ, звідсиReferenceError, а неundefined. - Використовувати
varу циклі з асинхронними колбеками. Одна спільна змінна на весь цикл дає класичний результат3, 3, 3замість0, 1, 2. - Покладатися на те, що
varза межами блока «просто працює». Це джерело випадкових перезаписів і конфліктів імен у великому файлі. - Очікувати
window.myLetу браузері. Змінніletіconstне потрапляють у глобальний об'єкт, тому такий доступ дастьundefined.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.