let

Оператор let оголошує локальну змінну блочної області видимості, з необов'язковим присвоєнням їй початкового значення.

Синтаксис

let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN];

Параметри

var1, var2, …, varN
Імена змінної або змінних, що оголошуються. Кожне ім'я має бути дозволеним ідентифікатором JavaScript.
value1, value2, …, valueN Optional
Для кожної оголошеної змінної ви можете вказати її початкове значення будь-яким дозволеним виразом JavaScript.

Опис

Оператор let дозволяє оголошувати змінні, що обмежені областю видимості блоку або виразу, для якого використовуються, на відміну від ключового слова var, яке визначає змінну глобально, чи локально для всієї функції, незалежно від області видимості блоку. Інша відмінність між операторами var та let полягає в тому, що останній ініціалізується тільки після оцінювання синтаксичним аналізатором (дивіться нижче).

Як і const, let не створює властивостей об'єкта window при глобальному оголошенні (у області видимості верхнього рівня).

Пояснення, чому була обрана назва "let" можна подивитись тут.

Правила області видимості

Областю видимості змінних, оголошених через 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 = 'глобальна';
let y = 'глобальна';
console.log(this.x); // "глобальна"
console.log(this.y); // undefined

Імітація приватних членів

Працюючи з конструкторами, можна використовувати let-зв'язування для створення приватних членів без використання замикань:

var Thing;

{
  let privateScope = new WeakMap();
  let counter = 0;

  Thing = function() {
    this.someProperty = 'foo';
    
    privateScope.set(this, {
      hidden: ++counter,
    });
  };

  Thing.prototype.showPublic = function() {
    return this.someProperty;
  };

  Thing.prototype.showPrivate = function() {
    return privateScope.get(this).hidden;
  };
}

console.log(typeof privateScope);
// "undefined"

var thing = new Thing();

console.log(thing);
// Thing {someProperty: "foo"}

thing.showPublic();
// "foo"

thing.showPrivate();
// 1

Такий самий шаблон приватності з використанням замикань для локальних змінних можна створити через var, але це потребує функціональної області видимості (зазвичай, це НВФВ у шаблоні модуль) замість просто блочної області видимості у вищенаведеному прикладі.

Повторні оголошення

Повторне оголошення тієї самої змінної у області видимості тієї самої функції чи блоку спричиняє помилку 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;
  }
}

Тимчасова мертва зона

На відміну від змінних, оголошених через var, які спочатку мають значення undefined, let-змінні не ініціалізуються, поки не відбудеться оцінювання їхнього оголошення. Звернення до змінної до ініціалізації призводить до викидання ReferenceError. Змінна знаходиться у "тимчасовій мертвій зоні" від початку блоку і до проходження ініціалізації.

function do_something() {
  console.log(bar); // undefined
  console.log(foo); // ReferenceError
  var bar = 1;
  let foo = 2;
}

Тимчасова мертва зона та typeof

На відміну від просто неоголошених змінних та змінних, що містять значення undefined, використання оператора typeof для перевірки типу змінної, що знаходиться у своїй ТМЗ, викине ReferenceError:

// виведе 'undefined'
console.log(typeof undeclaredVariable);
// призведе до 'ReferenceError'
console.log(typeof i);
let i = 10;

Ще один приклад тимчасової мертвої зони у поєднанні з лексичною областю видимості

Через наявність лексичної області видимості, ідентифікатор foo у виразі (foo + 55) оцінюється як ідентифікатор foo блоку if, а не розташована вище змінна foo зі значенням 33.

У цьому конретному рядку змінна foo блоку if вже була створена у лексичному середовищі, але ще не пройшла (і перервала) свою ініціалізацію (яка є частиною інструкції).

Змінна foo блоку if досі у тимчасовій мертвій зоні.

function test(){
   var foo = 33;
   if (true) {
      let foo = (foo + 55); // ReferenceError
   }
}
test();

Цей феномен може заплутати, наприклад, у наступній ситуації. Інструкція let n of n.a вже знаходиться всередині приватної області видимості блоку циклу for. Отже, ідентифікатор n.a вважається властивістю 'a' об'єкта 'n', розташованого у першій частині цієї ж інструкції ("let n").

Він досі знаходиться у тимчасовій мертвій зоні, оскільки його оголошення ще не було виконано та перервалось.

function go(n) {
  // n тут визначений!
  console.log(n); // Object {a: [1,2,3]}

  for (let n of n.a) { // ReferenceError
    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, наведена нижче, спричинить SyntaxError через підняття var наверх блоку. Це призводить до неявного повторного оголошення змінної.

let x = 1;

{
  var x = 2; // SyntaxError через повторне оголошення
}

Специфікації

Специфікація Статус Коментар
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Let and Const Declarations' in that specification.
Standard Початкове визначення. Не визначає let-вирази та let-блоки.
ECMAScript Latest Draft (ECMA-262)
The definition of 'Let and Const Declarations' in that specification.
Draft

Сумісність з веб-переглядачами

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
letChrome Full support 49
Full support 49
No support 48 — 49
Notes Disabled
Notes Support outside of strict mode.
Disabled From version 48 until version 49 (exclusive): this feature is behind the Enable Experimental JavaScript Features preference. To change preferences in Chrome, visit chrome://flags.
No support 41 — 49
Notes
Notes Strict mode is required.
Edge Full support 14
Full support 14
No support 12 — 14
Notes
Notes In Edge 12 and 13, let within a for loop initializer does not create a separate variable for each loop iteration as defined by ES2015. Instead, it behaves as though the loop were wrapped in a scoping block with the let immediately before the loop.
Firefox Full support 44
Notes
Full support 44
Notes
Notes Prior to Firefox 44, let is only available to code blocks in HTML wrapped in a <script type="application/javascript;version=1.7"> block (or higher version) and has different semantics (e.g. no temporal dead zone).
Notes Prior to Firefox 46, a TypeError is thrown on redeclaration instead of a SyntaxError.
Notes Firefox 54 adds support of let in workers.
IE Partial support 11
Notes
Partial support 11
Notes
Notes In Internet Explorer, let within a for loop initializer does not create a separate variable for each loop iteration as defined by ES2015. Instead, it behaves as though the loop were wrapped in a scoping block with the let immediately before the loop.
Opera Full support 17Safari Full support 10WebView Android Full support 49
Full support 49
No support 41 — 49
Notes
Notes Strict mode is required.
Chrome Android Full support 49
Full support 49
No support 48 — 49
Notes Disabled
Notes Support outside of strict mode.
Disabled From version 48 until version 49 (exclusive): this feature is behind the Enable Experimental JavaScript Features preference. To change preferences in Chrome, visit chrome://flags.
No support 41 — 49
Notes
Notes Strict mode is required.
Firefox Android Full support 44
Notes
Full support 44
Notes
Notes Prior to Firefox 44, let is only available to code blocks in HTML wrapped in a <script type="application/javascript;version=1.7"> block (or higher version) and has different semantics (e.g. no temporal dead zone).
Notes Prior to Firefox 46, a TypeError is thrown on redeclaration instead of a SyntaxError.
Notes Firefox 54 adds support of let in workers.
Opera Android Full support 18Safari iOS Full support 10Samsung Internet Android Full support 5.0
Full support 5.0
No support 4.0 — 5.0
Notes
Notes Strict mode is required.
nodejs Full support 6.0.0

Legend

Full support  
Full support
Partial support  
Partial support
See implementation notes.
See implementation notes.
User must explicitly enable this feature.
User must explicitly enable this feature.

Див. також