Skip to main content

Область видимості var, let і const

var має функціональну область видимості, а let і const - блочну, тому змінна, оголошена через var усередині if або циклу, «витікає» у всю функцію, а let і const залишаються всередині своїх фігурних дужок. Крім області видимості вони відрізняються поведінкою при hoisting, можливістю повторного оголошення і можливістю переприсвоєння.

Теорія

TL;DR

  • var - функціональна область видимості (function scope), let і const - блочна (block scope).
  • Підіймаються (hoisted) всі три, але var ініціалізується значенням undefined, а let і const до рядка оголошення перебувають у TDZ і кидають ReferenceError.
  • Повторне оголошення в тій самій області: var дозволяє, let і const дають SyntaxError.
  • Переприсвоєння: var і let дозволяють, const забороняє, але мутація об'єкта за посиланням дозволена.
  • Сучасна практика: const за замовчуванням, let за потреби, var - тільки в старому коді.

Швидкий приклад

javascript
function test() { if (true) { var x = 1; let y = 2; const z = 3; } console.log(x); // 1 console.log(y); // ReferenceError console.log(z); // ReferenceError } test();

x доступний, бо var «ігнорує» блок if і піднімається на рівень функції. y і z видно тільки всередині if.

Область видимості: функція проти блоку

Ключове словоОбласть видимості
varФункціональна (function scope)
let, constБлочна (block scope)

Функціональна область означає, що змінну видно у всій функції, де її оголошено, незалежно від блоку {}.

Блочна область означає, що змінну видно тільки всередині блоку { ... }, де її оголошено: тіло if, тіло циклу, будь-які фігурні дужки.

Hoisting і TDZ

Усі змінні підіймаються (hoisted) на початок своєї області видимості, але поводяться по-різному.

Ключове словоПідіймаєтьсяЧи можна використати до оголошення?
varтактак, але значення буде undefined
let, constтакні, помилка через TDZ (temporal dead zone)

Приклад з var:

javascript
console.log(a); // undefined var a = 10;

JavaScript «піднімає» саме оголошення var a, але не присвоєння a = 10.

Приклад з let і const:

javascript
console.log(b); // ReferenceError let b = 20;

Хоча b теж підіймається, вона перебуває у «тимчасовій мертвій зоні» (TDZ): від початку області видимості до фактичного рядка оголошення. Будь-яке звернення в цьому проміжку кидає ReferenceError.

Повторне оголошення і переприсвоєння

Ключове словоЧи можна оголосити повторно?
varТак, перезапише значення
let, constНі, SyntaxError
javascript
var x = 1; var x = 2; // дозволено console.log(x); // 2 let y = 1; let y = 2; // SyntaxError
Ключове словоЧи можна змінити значення?
varТак
letТак
constНі, але об'єкт усередині можна мутувати
javascript
let name = 'Maria'; name = 'Oleh'; // дозволено const user = { name: 'Maria' }; user.name = 'Oleh'; // дозволено: мутуємо об'єкт user = {}; // TypeError: не можна переприсвоїти посилання

const фіксує саме прив'язку (binding), тобто посилання, а не вміст об'єкта. Щоб заморозити і вміст, потрібен Object.freeze.

Приклад, що показує всі відмінності

javascript
function demo() { console.log(a); // undefined // console.log(b); // ReferenceError // console.log(c); // ReferenceError var a = 1; let b = 2; const c = 3; if (true) { var a = 10; // та сама змінна! let b = 20; // нова змінна const c = 30; // нова змінна console.log(a, b, c); // 10 20 30 } console.log(a, b, c); // 10 2 3 } demo();

var a «витекла» з блоку і перезаписала зовнішнє значення, а let і const створили власні локальні змінні всередині блоку, тому зовнішні b і c залишились недоторканими.

Що використовувати на практиці

Ключове словоКоли використовувати
letДля змінних, значення яких треба міняти
constЗа замовчуванням, завжди, якщо не потрібно міняти посилання
varНіколи, тільки для підтримки старого коду

Підсумкова таблиця:

Властивістьvarletconst
Область видимостіФункціональнаБлочнаБлочна
ПідіймаєтьсяТакТакТак
Використання до оголошенняundefinedПомилка (TDZ)Помилка (TDZ)
Повторне оголошенняТакНіНі
ПереприсвоєнняТакТакНі
Сучасний стандартЗастарілийРекомендуєтьсяЗа замовчуванням

Типові помилки

  • Вважати, що var усередині if або for створює локальну змінну. Насправді вона належить усій функції і може перезаписати зовнішнє значення.
  • Плутати hoisting з «немає помилки». let і const теж підіймаються, просто звернення до них у TDZ падає з ReferenceError.
  • Думати, що const робить значення незмінним. Він забороняє лише переприсвоєння змінної, а поля об'єкта і елементи масиву мутувати можна.
  • Використовувати var у циклі разом з асинхронним кодом: усі ітерації бачитимуть одну змінну, тоді як let створює нову прив'язку на кожній ітерації.
  • Покладатись на повторне оголошення var як на «оновлення» змінної: це мовчазне перезаписування, яке ховає помилки.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.