let
Оголошення let
оголошує локальну змінну з блоковою областю видимості, необов'язково ініціалізуючи її значенням.
Спробуйте його в дії
Синтаксис
let name1;
let name1 = value1;
let name1 = value1, name2 = value2;
let name1, name2 = value2;
let name1 = value1, name2, /* …, */ nameN = valueN;
Параметри
nameN
Назва змінної або змінних для оголошення. Кожна з них повинна бути дійсним ідентифікатором JavaScript.
valueN
Необов'язковеДля кожної оголошеної змінної можна (необов'язково) задати її початкове значення, у вигляді будь-якого дійсного виразу JavaScript.
Замість цього, для оголошення змінних також може використовуватися Присвоєння з деструктуруванням.
let { bar } = foo; // де foo = { bar:10, baz:12 };
/* Це створює змінну з назвою 'bar', котра має значення 10 */
Опис
let
дає змогу оголошувати змінні, котрі обмежені областю видимості інструкції-блоку, або виразу, на якому їх використовують, на відміну від ключового слова var
, котре оголошує змінну глобально, або локально – для всієї функції, без огляду на блоки.
Інша відмінність між var
і
let
полягає в тому, що до оголошеної за допомогою let
змінної можна звертатися лише після такого оголошення (читайте про темпоральну мертву зону). Через це оголошення let
називають непіднімними.
Як і const
, let
не створює властивостей об'єкта window
, коли оголошення відбувається глобально (в області видимості найвищого рівня).
Пояснення того, чому було обрано саме слово "let", можна прочитати тут.
Багатьох проблем зі змінними let
можна уникнути шляхом оголошення їх нагорі області видимості, в котрій вони використовуються (це може вплинути на читабельність).
На відміну від var
, словом let
починаються оголошення, а не інструкції. Це означає, що не можна використовувати самотнє оголошення let
як тіло блока (що має зміст, оскільки в такому разі не було б змоги звернутися до змінної).
if (true) let a = 1; // SyntaxError: Lexical declaration cannot appear in a single-statement context
Приклади
Правила областей видимості
Змінні, оголошені за допомогою let
, мають свою область видимості в межах блоку, для якого оголошені, а також вміщених в нього підблоків.
Щодо цього let
працює вельми подібно до var
.
Головна відмінність – те, що область видимості змінної var
– уся функція навколо:
function varTest() {
var x = 1;
{
var x = 2; // та сама змінна!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
{
let x = 2; // інша змінна
console.log(x); // 2
}
console.log(x); // 1
}
На верхньому рівні програм та функцій, let
, на відміну від var
, не створює властивості у глобальному об'єкті.
Наприклад:
var x = "global";
let y = "global";
console.log(this.x); // "global"
console.log(this.y); // undefined
Повторні оголошення
Повторне оголошення тієї ж змінної всередині тієї ж функційної або блокової області видимості спричиняє SyntaxError
.
if (x) {
let foo;
let foo; // викидається SyntaxError.
}
Можна зустріти помилки в інструкціях switch
, бо в таких випадках є лише один блок.
let x = 1;
switch (x) {
case 0:
let foo;
break;
case 1:
let foo; // SyntaxError через повторне оголошення.
break;
}
Блок, вкладений у гілку case, утворить нове лексичне оточення блокової області видимості, запобігши помилкам повторного оголошення, показаним вище.
let x = 1;
switch (x) {
case 0: {
let foo;
break;
}
case 1: {
let foo;
break;
}
}
При експериментах у REPL, як то вебконсолі Firefox (Інструменти > Інструменти веброзробника > Консоль), якщо запустити два оголошення let
з однаковою назвою у двох окремих введеннях, можна отримати таку ж помилку повторного оголошення. Обговорення цієї проблеми можна прочитати у ваді Firefox 1580891. Консоль Chrome дозволяє повторні оголошення let
в окремих введеннях REPL.
Темпоральна мертва зона (TDZ)
Про змінні let
і const
кажуть, що вони перебувають в "темпоральній мертвій зоні" (TDZ) від початку блоку і поки виконання коду не досягне рядка, на якому оголошена та ініціалізована відповідна змінна.
Поки змінна в TDZ — вона іще не ініціалізована значенням, і будь-які спроби звернутися до неї призведуть до ReferenceError
.
Ця змінна ініціалізується значенням, коли виконання досягає рядка коду, на якому вона оголошена.
Якщо при оголошенні змінної не задано жодного початкового значення, вона ініціалізується значенням undefined
.
Змінні var
працюють не так: вони повертають значення undefined
, якщо звернутися до них до їхнього оголошення.
Код нижче демонструє різницю результатів звертання до let
і var
вище рядків, на яких вони оголошені.
{
// TDZ починається на початку області видимості
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2; // Кінець TDZ (для foo)
}
Тут вжитий термін "темпоральний", тому що ця зона (TDZ) залежить від порядку виконання (часу), а не порядку, в якому написаний код (позиції). Наприклад, код нижче – працює, тому що навіть попри те, що функція, котра використовує змінну let
, стоїть вище за оголошення цієї змінної, вона викликається поза TDZ.
{
// TDZ почитається на початку області видимості
const func = () => console.log(letVar); // OK
// В межах TDZ звертання до letVar викидає `ReferenceError`
let letVar = 3; // Кінець TDZ (для letVar)
func(); // Викликано поза TDZ!
}
TDZ і typeof
Застосування оператора typeof
до змінної let
у її TDZ викине ReferenceError
:
// призводить до 'ReferenceError'
console.log(typeof i);
let i = 10;
Це відрізняється від застосування typeof
до неоголошених змінних, а також змінних, що мають значення undefined
:
// друкує 'undefined'
console.log(typeof undeclaredVariable);
TDZ вкупі з лексичною областю видимості
Наступний код призводить до ReferenceError
на вказаному рядку:
function test() {
var foo = 33;
if (foo) {
let foo = foo + 55; // ReferenceError
}
}
test();
Блок if
обчислюється, тому що зовнішня var foo
має значення.
Проте у зв'язку з лексичною областю видимості це значення недоступне всередині блоку: ідентифікатор foo
всередині цього блоку if
відповідає let foo
.
Вираз (foo + 55)
викидає ReferenceError
, тому що ініціалізація let foo
не була завершена: ця змінна іще перебуває в темпоральній мертвій зоні.
Цей феномен може збивати з пантелику в ситуаціях штибу наступної.
Інструкція let n of n.a
– зразу в приватній області видимості блоку циклу.
Таким чином, ідентифікатор n.a
вирішується до властивості 'a
' об'єкта 'n
', розташованого в першій частині самої інструкції (let n
).
Все це все одно знаходиться в темпоральній мертвій зоні, адже інструкція оголошення не була досягнута й закінчена.
function go(n) {
// n тут – означено!
console.log(n); // { a: [1, 2, 3] }
// ReferenceError на наступному рядку
for (let n of n.a) {
console.log(n);
}
}
go({ a: [1, 2, 3] });
Інші ситуації
Бувши вжитим усередині блоку, let
обмежує область видимості змінної цим блоком.
Зверніть увагу на різницю з var
, чия область видимості – функція, в котрій відбулось оголошення.
var a = 1;
var b = 2;
if (a === 1) {
var a = 11; // область видимості – глобальна
let b = 22; // область видимості – блок if
console.log(a); // 11
console.log(b); // 22
}
console.log(a); // 11
console.log(b); // 2
Проте поєднання оголошень var
і let
нижче – синтаксична помилка
, у зв'язку з тим, що var
піднімається нагору блоку.
Це призводить до неявного повторного оголошення змінної.
let x = 1;
{
var x = 2; // SyntaxError через повторне оголошення
}
Специфікації
Сумісність із браузерами
desktop | mobile | server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
let
|
Chrome Full support 49 | Edge Full support 14 | Firefox Full support 44 | Internet Explorer Partial support 11 | Opera Full support 17 | Safari Full support 10 | WebView Android Full support 49 | Chrome Android Full support 49 | Firefox for Android Full support 44 | Opera Android Full support 18 | Safari on iOS Full support 10 | Samsung Internet Full support 5.0 | Deno Full support 1.0 | Node.js Full support 6.0.0 |