Питання У чому різниця між використанням "let" та "var" оголошувати змінну в JavaScript?


ECMAScript 6 введено в let заява. Я чув, що це описано як "локальна" змінна, але я все ще не зовсім впевнений, як вона поводиться інакше, ніж var ключове слово

Які відмінності? Коли треба let бути використаний var?


3259
2018-04-17 20:09


походження


ECMAScript є стандартним і let входить до складу Випуск 6-го випуску і, швидше за все, буде в остаточному викладі. - Richard Ayotte
Побачити kangax.github.io/es5-compat-table/es6 для найсучаснішої матриці підтримки функцій ES6 (включаючи дозволу). На момент написання Firefox, Chrome та IE11 всі підтримують це (хоча, на мою думку, реалізація FF не є цілком стандартною). - Nico Burns
Довгий час я не знав, що vars в for-loop були обмежені функцією, яку вона загорнула. Я пам'ятаю, що це вперше з'ясувалося, і думала, що це дуже дурне. Я бачу деяку потужність, хоча тепер я знаю, як ці два можуть бути використані з різних причин, і як у деяких випадках ви, насправді, хочете використовувати var у циклі для циклу і не матимете його області блоку. - Eric Bishard
Оскільки підтримка функцій ES6 покращується, питання щодо прийняття ES6 зміщується на фоні від підтримки функцій до відмінностей у продуктивності. Як такий, Ось сайт, у якому я знайшов відмінності в продуктивності порівняння між ES6 і ES5. Пам'ятайте, що з часом воно, ймовірно, зміниться, оскільки двигуни оптимізуються для коду ES6. - timolawl
Це дуже гарне читання wesbos.com/javascript-копіювання - onmyway133


Відповіді:


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

Також змінні оголошуються з let не доступні до того, як вони будуть оголошені в їхньому приєднаному блоці. Як видно в демонстраційній версії, це викличе виняток із ReferenceError.

Демонстрація: 

var html = '';

write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible

try {
  write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
  write('globalLet: exception');
}

write('\nset variables');

var globalVar = 'globalVar';
let globalLet = 'globalLet';

write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);

function functionScoped() {
  write('\n#### function ####');
  write('\nfunctionVar: ' + functionVar); //undefined, but visible

  try {
    write('functionLet: ' + functionLet); //undefined, *not* visible
  } catch (exception) {
    write('functionLet: exception');
  }

  write('\nset variables');

  var functionVar = 'functionVar';
  let functionLet = 'functionLet';

  write('\nfunctionVar: ' + functionVar);
  write('functionLet: ' + functionLet);
}

function blockScoped() {
  write('\n#### block ####');
  write('\nblockVar: ' + blockVar); //undefined, but visible

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }

  for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
    write('\nblockVar: ' + blockVar); // visible here and whole function
  };

  for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
    write('blockLet: ' + blockLet); // visible only here
  };

  write('\nblockVar: ' + blockVar);

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }
}

function write(line) {
  html += (line ? line : '') + '<br />';
}

functionScoped();
blockScoped();

document.getElementById('results').innerHTML = html;
<pre id="results"></pre>

Глобальний:

Вони дуже схожі, коли вони використовуються як поза функціональним блоком.

let me = 'go';  // globally scoped
var i = 'able'; // globally scoped

Тим не менш, глобальні змінні визначені з let не буде додано як властивості на глобальному рівні window об'єкт, як і ті, що визначені з var.

console.log(window.me); // undefined
console.log(window.i); // 'able'

Функція:

Вони ідентичні, коли вони використовуються у функціональному блоці.

function ingWithinEstablishedParameters() {
    let terOfRecommendation = 'awesome worker!'; //function block scoped
    var sityCheerleading = 'go!'; //function block scoped
}

Блок:

Ось різниця. let видно лише в for() петля і var видно для всієї функції.

function allyIlliterate() {
    //tuce is *not* visible out here

    for( let tuce = 0; tuce < 5; tuce++ ) {
        //tuce is only visible in here (and in the for() parentheses)
        //and there is a separate tuce variable for each iteration of the loop
    }

    //tuce is *not* visible out here
}

function byE40() {
    //nish *is* visible out here

    for( var nish = 0; nish < 5; nish++ ) {
        //nish is visible to the whole function
    }

    //nish *is* visible out here
}

Повторна заява:

Припускаючи строгий режим, var дозволить вам повторно оголосити ту саму змінну у тій самій області. З іншого боку, let не буде:

'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.

4571
2018-05-27 10:16



Отже, мета полягає в тому, щоб дати виписки тільки для того, щоб звільнити пам'ять, коли вона не потрібна в певному блоці? - NoBugs
@NoBugs, так, і це заохочується, що змінні існують тільки там, де вони потрібні. - batman
let блок вираження let (variable declaration) statement є нестандартним і буде вилучено в майбутньому, bugzilla.mozilla.org/show_bug.cgi?id=1023609. - Gajus
їхня різниця в глобальному масштабі: let не додавати властивості до глобальної змінної 2ality.com/2015/02/es6-scoping.html#the_global_object - Yukulélé
@ThinkingStiff: будь ласка, перегляньте цей мета-пост, і зважити на технічні питання, що виникають. - Robert Harvey♦


let також може бути використаний для уникнення проблем із закриттями. Він пов'язує свіже значення, а не зберігає стару посилання, як показано в прикладах нижче.

DEMO

for(var i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

Указаний вище код демонструє класичну проблему закриття JavaScript. Посилання на i змінна зберігається в закритті обробника кліків, а не за фактичним значенням i.

Кожен обробник кліків посилається на один і той же об'єкт, оскільки в ньому є лише один лічильник, який містить 6, тому ви отримуєте 6 під час кожного клацання.

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

DEMO (Тестовано в Chrome і Firefox 50)

'use strict';

for(let i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

451
2018-04-17 20:11



Це насправді круто. Я б очікував, що "i" буде визначено за межами тіла циклу, що містяться в дужках, і НЕ формує "закриття" навколо "i". Звичайно ваш приклад доводить інакше. Я думаю, це трохи незрозуміло з синтаксичної точки зору, але цей сценарій настільки поширений, що має сенс підтримувати це таким чином. Дякую за те, що зробили це. - Karol Kolenda
IE 11 підтримує let, але це сповіщає "6" для всіх кнопок. Чи є у вас якесь джерело, яке говорить, як це зробити let повинен вести себе? - Jim Hunziker
Схоже, ваша відповідь - правильна поведінка: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - Jim Hunziker
Справді, це загальний порив у Javascript, і тепер я бачу чому let було б дуже корисно. Установка слухачів подій у циклі більше не вимагає виразу функції, що викликається безпосередньо, для локального обчислення i на кожній ітерації. - Adrian Moisa
Використання "let" просто усунуло цю проблему. Тому кожна ітерація створює приватну незалежну область блоків, але змінна "i" все ще може бути пошкоджена наступними змінами в блоці (надана змінна ітератора не зазвичай змінені в межах блоку, але інші заявлені змінні в межах блоку цілком можуть бути), і будь-яка декларована в межах блоку функція може, коли викликається, пошкодити значення "i" для інших функцій, оголошених у блоці, оскільки вони робити поділитися тим самим обсягом приватного блоку, звідси ж посилання на "я". - gary


Ось а пояснення let ключове слово з деякими прикладами.

Нехай працює дуже сильно, як var. Основна відмінність полягає в тому, що сфера змінної var - це вся функція, що вкладає

Ця таблиця на Wikipedia показує, які браузери підтримують Javascript 1.7.

Зауважте, що лише веб-переглядачі Mozilla та Chrome підтримують його. IE, Safari, а потенційно інші - ні.


131
2018-02-23 18:35



Ключовий біт тексту із зв'язаного документа виглядає так: "Дозвольте працювати дуже сильно, як var. Основна відмінність полягає в тому, що сфера змінної var - це вся функція, яка вкладає". - Michael Burr
Хоча це технічно правильно сказати, що IE не підтримує його, правильніше сказати, що це розширення лише для Mozilla. - olliej
@olliej, насправді Mozilla просто попереду гри. Див. Стор. 19 ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf - Tyler Crompton
@TylerCrompton це всього лише набір слів, які були зарезервовані протягом багатьох років. Коли додано Mozilla, це було чисто розширення Mozilla, без пов'язаних специфікацій. ES6 повинен визначити поведінку для повідомлень let, але це сталося після того, як Mozilla представив синтаксис. Пам'ятайте, що у Moz також є E4X, який є повністю мертвим і лише мозом. - olliej
IE11 додав підтримку для let  msdn.microsoft.com/en-us/library/ie/dn342892%28v=vs.85%29.aspx - eloyesp


Яка різниця між ними let і var?

  • Перемінник, визначений за допомогою a var Заява відома на протязі всього функція це визначено в, починаючи з функції. (*)
  • Перемінник, визначений за допомогою a let висловлювання відомо лише в блок він визначається в, з моменту, коли він визначається далі. (**)

Щоб зрозуміти різницю, розглянемо наступний код:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Тут ми бачимо, що наша змінна j відомо лише в першому для петлі, але не раніше і пізніше. Тим не менш, наша змінна i відомий у всій функції.

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


Це безпечно для використання let сьогодні?

Деякі люди стверджують, що в майбутньому ми будемо використовувати ТІЛЬКИ дозволеним твердженням, і що оператори statements var стануть застарілими. JavaScript гуру Кайл Сімпсон писав дуже детальна стаття про те, чому це не так.

Сьогодні, однак, це, безумовно, не так. Фактично, ми повинні насправді запитати себе, чи безпечно використовувати let заява Відповідь на це питання залежить від вашого середовища:

  • Якщо ви пишете серверний код JavaScript (Node.js), ви можете спокійно використовувати let заява

  • Якщо ви пишете код JavaScript на стороні клієнта та використовуєте трансплікатор (наприклад, Traceur), ви можете спокійно використовувати let висловлювання, однак ваш код, імовірно, буде нічим іншим, але оптимальним щодо продуктивності.

  • Якщо ви пишете код JavaScript на стороні клієнта та не використовуєте перешивач, вам слід розглянути підтримку веб-переглядача.

Сьогодні, 8 червня 2018 року, є ще деякі браузери, які не підтримують let!

enter image description here


Як відстежувати підтримку браузера

Для оновленого огляду, які браузери підтримують let Заява на момент прочитання вашої відповіді, див це Can I Use сторінка.


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

(**) Блокуються змінні не піднімаються


116
2018-06-02 20:59



щодо відповіді на 4: i IS відомий скрізь у функціональному блоці! Починається як undefined (через підйом), поки ви не призначите значення! ps: let також піднімається (до верхньої частини його містить блок), але дасть a ReferenceError коли згадується в блоці перед першим призначенням. (PS2: Я прокомпіллонів якийсь хлопець, але вам дійсно не потрібна точка з комою після коду). Це сказано, спасибі за додавання перевірки реальності щодо підтримки! - GitaarLAB
@GitaarLAB: згідно з Мережа розробників Mozilla : "У ECMAScript 2015, нехай зв'язування не підлягає змінному підйомнику, що означає, що декларації не дозволяють переходити до верхньої частини поточного контексту виконання". - У будь-якому випадку, я зробив кілька покращень у моїй відповіді, яка повинна уточнити різницю в підйомній поведінці між let і var! - John Slegers
Ваша відповідь покращилася (я ретельно перевірив). Зауважте, що той самий зв'язок, на який ви посилались у вашому коментарі, також говорить: "(нехай) змінна знаходиться в" тимчасовій мертвій зоні "з початок блоку поки не буде оброблено ініціалізацію ". Це означає, що" ідентифікатор "(текстовий рядок" зарезервовано ", щоб вказати" щось ") вже зарезервований у відповідній області, інакше він стане частиною області користування root / host / window. Особисто я "підняття" означає лише резервування / зв'язування декларованих "ідентифікаторів" до їх відповідної сфери; виключаючи їх ініціалізацію / призначення / модифікованість! - GitaarLAB
І .. + 1. Ця стаття Кайла Сімпсона, до якої ви зв'язали, є відмінно читай, дякую за це! Ясно також про "тимчасові мертві зони", ака "ТДЗ". Одна цікава річ, яку я хотів би додати: я прочитав на MDN, що let і const були Рекомендується використовувати лише тоді, коли вам дійсно потрібна їх додаткова функціональність, тому що примусове виконання / перевірка цих додаткових функцій (наприклад, констант тільки для запису) призводить до "додаткової роботи" (та додаткових вузлів-об'єктів у дереві масштабу) для (поточного) двигуна для виконання / перевірки / підтвердження / налаштування . - GitaarLAB


Прийнята відповідь відсутня така точка:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined

98
2018-04-17 21:38



Прийнята відповідь пояснює цю точку. - TM.
Прийнята відповідь НЕ пояснює цю точку в її прикладі. Прийнята відповідь лише продемонструвала це в for ініціалізатор петлі, різко звужуючи область застосування обмежень let. Присвоєно - Jon Davis
@ stimpy77 У ньому чітко сказано, що "дозволено визначити область найближчого оточуючого блоку"; чи має бути включений будь-який шлях, який виявляється? - Dave Newton
було багато прикладів, і ніхто з них не належним чином продемонстрував це питання. Я, можливо, погодився і на прийняту відповідь, і на цю? - Jon Davis
Цей вклад показує, що "блок" може бути просто набором ліній, що вкладені в дужки; тобто вона не повинна бути пов'язана з будь-яким контролем потоку, циклу тощо. - webelo


Є кілька тонких відмінностей - let Обчислення поводиться більш як змінне масштабування робить більш-менш будь-якими іншими мовами.

наприклад, Це залежить від блоку, що не містить їх. Вони не існують, перш ніж вони оголошуються, і т. Д.

Однак це варто відзначити let це лише частина новітніх реалізацій Javascript і має різний ступінь Підтримка браузера.


40
2018-03-06 10:41



Варто також відзначити, що ECMAScript є стандартним і let входить до складу Випуск 6-го випуску і, швидше за все, буде в остаточному викладі. - Richard Ayotte
Ось різниця 3 років робить: D - olliej
Просто зупиняючись на цьому питанні, і в 2012 році це все одно, що підтримують лише браузери Mozilla let. Safari, IE і Chome все це не є. - pseudosavant
Ідея випадкового створення часткової блокової сфери на аварію - це хороший момент, будьте обережні let не піднімає, використовувати змінну, визначену a let визначений у верхній частині вашого блоку. Якщо у вас є if вираження, яке є більш ніж декількома рядками коду, ви можете забути, що ви не можете використовувати цю змінну доти, доки вона не буде визначена. ВЕЛИКИЙ ПУНКТ !!! - Eric Bishard
@EricB: так і ні: "У ECMAScript 2015, let  буде підніматися змінна у верхній частині блоку. Проте посилання на змінну в блоці перед зазначенням змінної в a ReferenceError (моя примітка: замість старого доброго undefined) Ця змінна перебуває у "тимчасовій мертвій зоні" з початку блоку, доки не буде оброблено декларацію ". Те саме стосується і" операторів перемикання, оскільки є лише один базовий блок ". Джерело: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - GitaarLAB


Ось приклад різниці між двома (підтримка, що тільки почалася для chrome): enter image description here

Як ви можете побачити var j змінна досі має значення за межами діапазону для циклу (Block Scope), але це значення має значення let i змінна невизначена поза межами циклу для циклу.

"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
  console.log(j);
}

console.log(j);

console.log("let:");
for (let i = 0; i < 2; i++) {
  console.log(i);
}

console.log(i);


39
2017-11-23 22:52



Який інструмент я дивився тут? - Barton
Chrome devtools - vlio20
Як розробник настільних аплетів для кориці, я не піддавався таким блискучим інструментам. - Barton


let

Блок сфери

Змінні, оголошені за допомогою let Ключове слово є блокованим, що означає, що вони доступні лише в блок в якій вони були оголошені.

На верхньому рівні (поза функцією)

На верхньому рівні змінні оголошують використанням let не створювати властивості на глобальному об'єкті.

var globalVariable = 42;
let blockScopedVariable = 43;

console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43

console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined

Всередині функції

Всередині funciton (але поза блоком), let має такий же обсяг, як і var.

(() => {
  var functionScopedVariable = 42;
  let blockScopedVariable = 43;

  console.log(functionScopedVariable); // 42
  console.log(blockScopedVariable); // 43
})();

console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Всередині блоку

Перемінні оголошені використанням let Всередині блоку не можна отримати доступ за межами цього блоку.

{
  var globalVariable = 42;
  let blockScopedVariable = 43;
  console.log(globalVariable); // 42
  console.log(blockScopedVariable); // 43
}

console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Всередині петлі

Змінні оголошені з let в циклах можна посилатися лише всередині цього циклу.

for (var i = 0; i < 3; i++) {
  var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4

for (let k = 0; k < 3; k++) {
  let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.

Петлі з затворами

Якщо ви використовуєте let замість var в циклі з кожною ітерацією ви отримуєте нову змінну. Це означає, що ви можете безпечно використовувати замикання всередині петлі.

// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}

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

Тому що тимчасова мертва зона, змінні оголошені використанням let неможливо отримати доступ до їх оголошення. Спроба зробити це викидає помилку.

console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;

Немає повторного декларування

Ви не можете оголосити таку ж змінну кілька разів за допомогою let. Ви також не можете оголосити змінну, що використовує let з тим самим ідентифікатором, що і інша змінна, яка була оголошена використанням var.

var a;
var a; // Works fine.

let b;
let b; // SyntaxError: Identifier 'b' has already been declared

var c;
let c; // SyntaxError: Identifier 'c' has already been declared

const

const дуже схожий на let- це блокована область і TDZ. Є, однак, дві речі, які різні.

Немає перепризначення

Змінна оголошена використанням const не можна повторно призначити.

const a = 42;
a = 43; // TypeError: Assignment to constant variable.

Зауважте, що це не означає, що значення незмінне. Його властивості все ще можна змінити.

const obj = {};
obj.a = 42;
console.log(obj.a); // 42

Якщо ви хочете мати незмінний об'єкт, ви повинні використовувати його Object.freeze().

Ініціалізатор обов'язковий

Ви завжди повинні вказати значення при оголошенні змінної, що використовує const.

const a; // SyntaxError: Missing initializer in const declaration

38
2018-01-17 15:11





  • Змінна без підйому

    let воля не піднімай на весь обсяг блоку, в якому вони з'являються. Навпаки, var міг піднімати, як нижче.

    {
       console.log(cc); // undefined. Caused by hoisting
       var cc = 23;
    }
    
    {
       console.log(bb); // ReferenceError: bb is not defined
       let bb = 23;
    }
    

    Власне, Per @Bergi Обидва var і let піднімаються.

  • Сміттєвий збір

    Блок сфери let корисно відноситься до закупорювання та збирання сміття для повернення пам'яті. Розглянемо

    function process(data) {
        //...
    }
    
    var hugeData = { .. };
    
    process(hugeData);
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
    

    The click обробник зворотного виклику не потребує hugeData змінна взагалі. Теоретично, після process(..) бігає, величезна структура даних hugeData може бути зібрана сміття. Тим не менш, можливо, що деякий JS двигун все одно буде тримати цю величезну структуру, оскільки click функція має закриття на весь спектр.

    Проте обсяг блоків може зробити цю величезну структуру даних збирати сміття.

    function process(data) {
        //...
    }
    
    { // anything declared inside this block can be garbage collected
        let hugeData = { .. };
        process(hugeData);
    }
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
    
  • let петлі

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

    // print '5' 5 times
    for (var i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }
    

    Однак замінити var з let

    // print 1, 2, 3, 4, 5. now
    for (let i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }
    

    Оскільки let створіть нове лексичне середовище з такими іменами для: a) ініціалізатора; b) кожну ітерацію (попередньо для оцінки вираження приросту), більш детальна інформація тут.


20
2018-03-22 14:39



Насправді вони все ще піднімаються - Bergi
У них вони піднімаються, але поводяться так, ніби не піднімаються через (барабанний рулон) Temporal Dead Zone - дуже драматичне ім'я для ідентифікатора, недоступного, доки його не оголошують :-) - Drenai
Тож нехай піднімається, але недоступна? Як це відрізняється від "не піднято"? - N-ate
Сподіваємось, Брайан або Бергі повернуться, щоб відповісти на це. Чи є декларація пропущення, але не призначення? Дякую! - N-ate
@ Н-ї, ось один пост Бергі, можливо, ви можете знайти відповідь на це. - zangw


Головна відмінність - це обсяг різниця, в той час як дозволяти може бути доступний лише всередині оголошеного обсягу, як у циклі, var може бути доступний за межами петлі, наприклад. З документації в Росії MDN (приклади також з MDN):

дозволяти дозволяє оголосити змінні, обмежені сферою дії блоку, виписки чи виразу, на якому він використовується. Це на відміну від var ключове слово, яке визначає змінну глобально або локально для всієї функції незалежно від області блоків.

Змінні оголошені дозволяти мають в своєму розпорядженні блок, в якому вони визначені, а також у будь-яких містяться підблоки. Таким чином, дозволяти дуже сильно працює var. Головна відмінність полягає в тому, що сфера застосування a var змінна - це ціла функція, що замикає:

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}`

На вищому рівні програм і функцій дозволяти, на відміну від var, не створює властивості на глобальному об'єкті. Наприклад:

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

Коли використовується всередині блоку, нехай обмежує область дії змінної до цього блоку. Зверніть увагу на різницю між var обсяг якого знаходиться всередині функції, де вона оголошена.

var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block

  console.log(a);  // 11
  console.log(b);  // 22
} 

console.log(a); // 11
console.log(b); // 2

Також не забувайте, що це функція ECMA6, тому вона ще не повністю підтримується, тому краще завжди передавати її в ECMA5, використовуючи Babel та ін ... для отримання додаткової інформації про відвідування веб-сайт babel


15
2017-08-18 00:58