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 (ECMA-262)
The definition of 'Let and Const Declarations' in that specification.
Living Standard

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

BCD tables only load in the browser

Див. також