Яка різниця між використанням "дозволити" та "вар"?


4537

Введено ECMAScript 6 це letтвердження .

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

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


104
ECMAScript є стандартом і letміститься в проекті 6-го видання і, швидше за все, буде в остаточній специфікації.
Річард Айотт

5
Дивіться у kangax.github.io/es5-compat-table/es6 для найновішої підтримки матриці функцій ES6 (у тому числі нехай). На момент написання Firefox, Chrome та IE11 всі це підтримують (хоча я вважаю, що реалізація FF не зовсім стандартна).
Ніко Бернс

22
Найдовше я не знав, що варси в циклі for for присвоюються функції, в яку він був завершений. Я пам’ятаю, що це вперше зрозумів і подумав, що це дуже дурно. Я бачу деяку силу, хоча зараз знаю, як обидва можуть бути використані для різних причин, і як у деяких випадках ви можете насправді хотіти використовувати var у циклі for, а не мати його до блоку.
Ерік Бішард

1
Це дуже гарне читання wesbos.com/javascript-scoping
onmyway133

1
Добре пояснена відповідь тут stackoverflow.com/a/43994458/5043867
Pardeep Jain

Відповіді:


6096

Правила визначення рівня

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

function run() {
  var foo = "Foo";
  let bar = "Bar";

  console.log(foo, bar);

  {
    let baz = "Bazz";
    console.log(baz);
  }

  console.log(baz); // ReferenceError
}

run();

Причина того, що letключове слово було введено в мову - сфера функцій, є заплутаною і була одним з основних джерел помилок у JavaScript.

Подивіться на цей приклад з іншого питання про stackoverflow :

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

My value: 3був виведений на консоль кожного разу, funcs[j]();коли анонімні функції прив'язувалися до однієї змінної.

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

Підйомник

Хоча змінні, задекларовані за допомогою varключового слова, піднімаються (ініціалізуються undefinedдо запуску коду), що означає, що вони доступні у своїй охоплюючій області ще до їх оголошення:

function run() {
  console.log(foo); // undefined
  var foo = "Foo";
  console.log(foo); // Foo
}

run();

letзмінні не ініціалізуються, поки не буде визначено їх визначення. Доступ до них перед ініціалізацією призводить до а ReferenceError. Змінна, про яку йдеться, знаходиться у "тимчасовій мертвій зоні" від початку блоку до обробки ініціалізації.

function checkHoisting() {
  console.log(foo); // ReferenceError
  let foo = "Foo";
  console.log(foo); // Foo
}

checkHoisting();

Створення глобальної властивості об'єкта

На верхньому рівні, letна відміну від цього var, не створюється властивість глобального об'єкта:

var foo = "Foo";  // globally scoped
let bar = "Bar"; // globally scoped

console.log(window.foo); // Foo
console.log(window.bar); // undefined

Передекларація

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

'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.

let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared

23
Пам'ятайте, що ви можете створювати блок коли завгодно. function () {код; {нехай inBlock = 5; } код; };
середній Джо

177
Отож, цілі дозволяють операторам лише звільнити пам'ять, коли вони не потрібні в певному блоці?
NoBugs

219
@NoBugs, так, і рекомендується, щоб змінні існували лише там, де вони потрібні.
Бетмен

67
letВираз блоку let (variable declaration) statementє нестандартним і його буде видалено в майбутньому, bugzilla.mozilla.org/show_bug.cgi?id=1023609 .
Гаджус

19
Тож я просто не можу придумати жоден випадок, коли використання var не має користі. Чи може хтось надати мені приклад ситуації, коли бажано використовувати var?
Луїс Сієра

621

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

for(var i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

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

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

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

(Випробувано в Chrome і Firefox 50)

for(let i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Clicking on each number will log to console:</p> 
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>


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

9
IE 11 підтримує let, але він попереджає "6" для всіх кнопок. Чи є у вас якесь джерело, яке говорить про те, як letслід поводитися?
Джим Ханзікер

10
Схоже, ваша відповідь - правильна поведінка: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jim Hunziker

11
Дійсно, це загальна проблема в Javascript, і тепер я можу зрозуміти, чому це letбуло б дуже корисно. Налаштування слухачів подій у циклі більше не вимагає прямого виклику функції вираження для локального визначення часу iна кожній ітерації.
Адріана Мойса

19
Використання "нехай" просто відкладає цю проблему. Таким чином, кожна ітерація створює приватний незалежний блок блоку, але змінна "i" все ще може бути пошкоджена наступними змінами всередині блоку (надана змінна ітератора зазвичай не змінюється всередині блоку, але інші заявлені змінні пускання всередині блоку цілком можуть бути) і будь-яка функція , оголошеної всередині блок може, при виклику, корумповане значення «я» для інших функцій , оголошеним в блоці , тому що вони роблять один і той же приватний блок обсяг , отже , те ж посилання на «я».
гарі

198

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

  • Змінна, визначена за допомогою varоператора, відома у всій функції, в якій вона визначена, з початку функції.(*)
  • Змінна, визначена за допомогою 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сьогодні?

Деякі люди стверджують, що в майбутньому ми будемо використовувати ТОЛЬКІ випуски висловлювань, а вар-заяви стануть застарілими. Гуру JavaScript Кайл Сімпсон написав дуже детальну статтю про те, чому він вважає, що так не буде .

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

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

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

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

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

    Є ще деякі браузери, які взагалі не підтримують let:

введіть тут опис зображення


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

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


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

(**) Змінні масштабу блоку не піднімаються


14
щодо відповіді v4: iIS відомий скрізь у функціональному блоці! Починається як undefined(за рахунок підйому), поки ви не призначите значення! ps: letтакож піднімається (до вершини, що містить блок), але дасть знак ReferenceErrorпри посиланні в блоці перед першим призначенням. (ps2: Я добрий хлопець з комою, але вам не потрібна крапка з комою після блоку). Це було сказано, дякую, що додав перевірку реальності щодо підтримки!
GitaarLAB

@GitaarLAB: За даними мережі розробників Mozilla : "У ECMAScript 2015 нехай прив'язки не підлягають змінній підйомі. Це означає, що нехай декларації не переміщуються до вершини поточного контексту виконання". - У будь-якому разі я внесла кілька вдосконалень у свою відповідь, які повинні прояснити різницю у підйомній поведінці між letта var!
John Slegers

1
Ваша відповідь значно покращилась (я ретельно перевірив). Зверніть увагу, що те саме посилання, на яке ви посилаєтесь у вашому коментарі, також говорить: "Змінна (нехай) знаходиться у" тимчасовій мертвій зоні "від початку блоку до обробки ініціалізації." Це означає, що 'ідентифікатор' (текстовий рядок 'зарезервовано' для вказівки на 'щось') вже зарезервований у відповідній області застосування, інакше він стане частиною області root / host / window. Для мене особисто "підйом" означає не що інше, як резервування / прив'язку оголошених "ідентифікаторів" до їх відповідного обсягу; виключаючи їх ініціалізацію / призначення / модифікованість!
GitaarLAB

І .. + 1. Ця стаття Кайла Сімпсона, яку ви зв'язали, - це чудове прочитання, дякую за це! Також зрозуміло про "тимчасову мертву зону", яка називається "TDZ". Одна цікава річ , яку я хотів би додати: Я прочитав на MDN , що letі constбуло рекомендовано використовувати лише коли ви на насправді потребують додаткової функціональності , оскільки виконання / перевірка ці додаткові функції (наприклад , тільки для запису сопзЬ) результату в «більше роботи '(та додаткові вузли області в дереві діапазону) для (поточного) двигуна (и) для забезпечення / перевірки / перевірки / налаштування.
GitaarLAB

1
Зауважте, що MDN говорить, що IE DO інтерпретувати нехай правильно. Що це таке? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Katinka

146

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

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

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

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


5
Ключовим бітом тексту зв'язаного документа, здається, "нехай працює дуже схоже на var. Основна відмінність полягає в тому, що сфера застосування змінної var - вся функція, що додається".
Майкл Берр

50
Хоча технічно правильно сказати, що IE не підтримує, правильніше сказати, що це лише розширення mozilla.
olliej

55
@olliej, насправді Mozilla випереджає гру. Див. Сторінку 19 з ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Тайлер Кромптон

@TylerCrompton - це лише набір слів, які зарезервовані роками. Коли мозіла додала, нехай це було суто розширення мозілла, без відповідних специфікацій. ES6 повинен визначати поведінку для висловлюваних повідомлень, але це відбулося після того, як mozilla представив синтаксис. Пам'ятайте, у мозку також є E4X, який повністю мертвий і лише моз.
olliej


112

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

{
  let a = 123;
};

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

19
Прийнята відповідь НЕ пояснює цей пункт у своєму прикладі. Прийнята відповідь лише продемонструвала її в forініціалізаторі циклу, різко звузивши сферу застосування обмежень let. Отримано.
Джон Девіс

37
@ stimpy77 У ньому прямо вказано "нехай буде скопійовано до найближчого огороджувального блоку"; чи потрібно включати всі маніфести?
Дейв Ньютон

6
прикладів було багато, і жоден з них не продемонстрував належну справу. Я, можливо, підтримав і прийняту відповідь, і цей?
Джон Девіс

5
Цей внесок демонструє, що "блок" може бути просто набором рядків, укладених у дужки; тобто це не потрібно асоціювати з яким-небудь потоком управління, циклом тощо.
webelo

81

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

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

Всередині функції (але поза блоком) 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

51

Ось приклад різниці між цими (підтримка, щойно розпочалася для chrome):
введіть тут опис зображення

Як ви бачите, 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);


2
Який інструмент я дивлюся тут?
Бартон

20
Chrome devtools
vlio20

Як розробник настільних аплетів для Cinnamon, я не зазнавав таких блискучих інструментів.
Бартон

48

Існують деякі тонкі відмінності - letмасштабування ведеться більше, як змінне масштабування в більш-менш інших мовах.

наприклад, він охоплює блок, що додається, вони не існують до того, як вони оголошені тощо.

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


11
Варто також зазначити, що ECMAScript є стандартом і letвходить в проект 6-го видання і, швидше за все, буде в остаточній специфікації.
Річард Айотт

23
Ось така різниця становить 3 роки: D
olliej

4
Щойно стикався з цим питанням, і в 2012 році, як і раніше, підтримують лише браузери Mozilla let. Сафарі, IE та Chome - все це не так.
псевдосавант

2
Ідея випадкового створення часткового блоку блоку на аварії - це хороший момент, будьте обережні, letне використовуйте змінну, визначену letвизначеною у верхній частині блоку. Якщо у вас є ifтвердження, яке перевищує лише кілька рядків коду, ви можете забути, що ви не можете використовувати цю змінну до того моменту, як вона буде визначена. ВЕЛИКИЙ БОК !!!
Ерік Бішард

2
@EricB: так і ні: "У ECMAScript 2015 let буде піднята змінна у верхній частині блоку. Однак, посилання на змінну в блоці до оголошення змінної призводить до ReferenceError (моя примітка: замість хорошого старого undefined). змінна знаходиться у "тимчасовій мертвій зоні" від початку блоку до обробки декларації. " Те ж саме стосується і "заяви операторів перемикання, оскільки є лише один базовий блок". Джерело: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GitaarLAB

26

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

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

Змінні, оголошені let, мають в своїй області блок, в якому вони визначені, а також у будь-яких містяться підблоках. Таким чином, нехай працює дуже схоже на var . Основна відмінність полягає в тому, що сфера застосування змінної 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


24
  • Змінна не піднімається

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

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

    Власне, Пер @ Бергі, обидва varі letпіднімаються .

  • Збір сміття

    letКорисний блок блоку стосується закриття та вивезення сміття для повернення пам'яті. Подумайте,

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

    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створити нове лексичне середовище з тими іменами для а) початкового виразу b) кожної ітерації (попередньо для оцінки виразного збільшення), тут детальніше .


4
Так, вони піднімаються, але поводяться так, ніби не піднімаються через (барабанний рулон) темпоральної мертвої зони - дуже драматичне ім'я для ідентифікатора, недоступного, поки не буде оголошено :-)
Drenai

Так нехай піднімається, але недоступно? Чим це відрізняється від "не піднімається"?
N-ate

Сподіваємось, Брайан або Бергі повернуться, щоб відповісти на це. Чи є декларація про відпущені підйомні, але не призначення? Дякую!
N-ate

1
@ N-ate, Ось один пост Берджі, можливо, ви можете знайти відповідь у ньому.
zangw

Це цікаво, що його навіть називають підйомом, коли справа дозволена. Я розумію, що технічно синтаксичний аналіз попередньо захоплює його, але для всіх намірів і цілей програміст повинен ставитися до нього так, ніби його не існує. З іншого боку, підйом вару має значення для програміста.
N-ate

19

Ось приклад для додавання до того, що вже написали інші. Припустимо, ви хочете створити масив функцій, adderFunctionsде кожна функція приймає один аргумент Number і повертає в масив суму аргументу та індекс функції. Спроба створення adderFunctionsз циклом за допомогою varключового слова не працюватиме так, як хтось може наївно очікувати:

// An array of adder functions.
var adderFunctions = [];

for (var i = 0; i < 1000; i++) {
  // We want the function at index i to add the index to its argument.
  adderFunctions[i] = function(x) {
    // What is i bound to here?
    return x + i;
  };
}

var add12 = adderFunctions[12];

// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000

// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true

Наведений вище процес не генерує потрібний масив функцій, оскільки iобласть дії виходить за межі ітерації forблоку, в якому створена кожна функція. Замість цього, наприкінці циклу, iзакриття кожної функції посилається на iзначення 'в кінці циклу (1000) для кожної анонімної функції в adderFunctions. Це зовсім не те, чого ми хотіли: зараз у нас є масив з 1000 різних функцій в пам'яті з точно такою ж поведінкою. І якщо ми згодом оновимо значення i, мутація вплине на всіadderFunctions .

Однак ми можемо спробувати ще раз за допомогою letключового слова:

// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];

for (let i = 0; i < 1000; i++) {
  // NOTE: We're using the newer arrow function syntax this time, but 
  // using the "function(x) { ..." syntax from the previous example 
  // here would not change the behavior shown.
  adderFunctions[i] = x => x + i;
}

const add12 = adderFunctions[12];

// Yay! The behavior is as expected. 
console.log(add12(8) === 20); // => true

// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined

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

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

const doubleAdderFunctions = [];

for (var i = 0; i < 1000; i++) {
    const j = i;
    doubleAdderFunctions[i] = x => x + i + j;
}

const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];

// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true

Не дозволяйте цього статися з вами. Використовуйте підводку.

ПРИМІТКА. Це приклад навчання, призначений для демонстрації var/ letповедінки в циклі та із закриттям функцій, які також легко зрозуміти. Це було б жахливим способом додавання чисел. Але загальна техніка збору даних в анонімних функціях закриття може зустрічатися в реальному світі в інших контекстах. YMMV.


2
@aborz: Також дуже крутий синтаксис анонімної функції у другому прикладі. Це просто те, до чого я звик у C #. Я сьогодні щось дізнався.
Бартон

Виправлення: З технічної точки зору описаний синтаксис функції стрілки => developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Barton

3
Насправді вам це не потрібно let value = i;. forОператор створює лексичний блок.
Зубна щітка

17

Різниця полягає в обсязі змінних, оголошених з кожною.

На практиці існує ряд корисних наслідків різниці в обсязі:

  1. letзмінні видимі лише в найближчому блоку, що їх додає ( { ... }).
  2. letзмінні можуть бути використані лише у рядках коду, які виникають після оголошення змінної (навіть якщо вони підняті !).
  3. letзмінні не можуть бути повторно оголошений на наступний varабо let.
  4. Глобальні letзмінні не додаються до глобального windowоб’єкта.
  5. letзмінні прості у використанні при закритті (вони не викликають перегонних умов ).

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

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

varможе все-таки бути корисним, якщо ви впевнені, що хочете отримати ефект єдиного прив'язки під час використання замикання в циклі (№5) або для оголошення зовнішніх видимих ​​глобальних змінних у вашому коді (№4). Використання varдля експорту може бути витіснено, якщо exportмігрує з транспілерного простору та на основну мову.

Приклади

1. Немає використання поза найближчим огороджувальним блоком: Цей блок коду призведе до помилки посилання, оскільки друге використання xвідбувається поза блоком, де воно оголошено за допомогою let:

{
    let x = 1;
}
console.log(`x is ${x}`);  // ReferenceError during parsing: "x is not defined".

На відміну від того ж прикладу з var творами.

2. Немає використання перед оголошенням:
Цей блок коду буде передбачати код, ReferenceErrorперш ніж його можна буде запустити x:

{
    x = x + 1;  // ReferenceError during parsing: "x is not defined".
    let x;
    console.log(`x is ${x}`);  // Never runs.
}

На відміну від цього, той самий приклад з varаналізами та запуском без викидів.

3. Немає передекларації: Наступний код демонструє, що змінна, декларована за допомогою, letне може бути передекларована пізніше:

let x = 1;
let x = 2;  // SyntaxError: Identifier 'x' has already been declared

4. Глобали, не приєднані до window:

var button = "I cause accidents because my name is too common.";
let link = "Though my name is common, I am harder to access from other JS files.";
console.log(link);  // OK
console.log(window.link);  // undefined (GOOD!)
console.log(window.button);  // OK

5. Легке використання із закриттями: Змінні, задекларовані з var, не працюють добре із замиканнями всередині циклів. Ось простий цикл, який виводить послідовність значень змінної iу різні моменти часу:

for (let i = 0; i < 5; i++) {
    console.log(`i is ${i}`), 125/*ms*/);
}

Зокрема, це результати:

i is 0
i is 1
i is 2
i is 3
i is 4

У JavaScript ми часто використовуємо змінні значно пізніше, ніж коли вони створюються. Коли ми демонструємо це, затримуючи вихід із закриттям, переданим на setTimeout:

for (let i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... вихід залишається незмінним, поки ми дотримуємося let. На противагу цьому, якби ми використовували var iзамість цього:

for (var i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... цикл несподівано виводить "i is 5" п'ять разів:

i is 5
i is 5
i is 5
i is 5
i is 5

5
№5 не спричинено умовами перегонів. Використовуючи varзамість let, код еквівалентний: var i = 0; while (i < 5) { doSomethingLater(); i++; } iзнаходиться поза закриттям, і за часом, який doSomethingLater()виконується, iвже збільшується в 5 разів, отже, вихід виходить у i is 5п’ять разів. Використовуючи let, змінна iзнаходиться в межах закриття, тому кожен виклик асинхронізації отримує власну копію, iа не використовує "глобальну", створену за допомогою var.
Даніель Т.

@DanielT. Я не думаю, що трансформація зняття визначення змінної з ініціалізатора циклу нічого не пояснює. Це просто нормальне визначення семантики for. Більш точною трансформацією, хоча і більш складною, є класична for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(i $ {j}, ), 125/*ms*/); })(i); }яка вводить "запис-активацію функції", щоб зберегти кожне значення iз назвою jвсередині функції.
mormegil

14

Нехай наступні дві функції показують різницю:

function varTest() {
    var x = 31;
    if (true) {
        var x = 71;  // Same variable!
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function letTest() {
    let x = 31;
    if (true) {
        let x = 71;  // Different variable
        console.log(x);  // 71
    }
    console.log(x);  // 31
}

13

let Це цікаво, оскільки дозволяє нам робити щось подібне:

(() => {
    var count = 0;

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

Що призводить до підрахунку [0, 7].

Тоді як

(() => {
    var count = 0;

    for (var i = 0; i < 2; ++i) {
        for (var i = 0; i < 2; ++i) {
            for (var i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

Число лише [0, 1].


2
це перший раз, коли я коли-небудь бачив, щоб хто-небудь діяв так, як бажане було змінне затінення. ні, мета нехай не дозволяє активізувати тіні
Джон Хауґленд

1
мета? це конструкція, ви можете використовувати її як завгодно, один із цікавих способів такий.
Дмитро

13

Функція блоку VS блоку:

Основна відмінність між varі letє те , що змінним , оголошеним з varє функція області дії . Тоді як функції, задекларовані з, letє об'єктом блоку . Наприклад:

function testVar () {
  if(true) {
    var foo = 'foo';
  }

  console.log(foo);
}

testVar();  
// logs 'foo'


function testLet () {
  if(true) {
    let bar = 'bar';
  }

  console.log(bar);
}

testLet(); 
// reference error
// bar is scoped to the block of the if statement 

змінні з var:

Коли перша функція testVarотримує виклик змінної foo, оголошеної за допомогою var, все ще доступна поза ifоператором. Ця змінна fooбула б доступна всюди в межах testVar функції .

змінні з let:

Коли друга функція testLetвикликається смужкою змінної, оголошеною з let, доступна лише всередині ifоператора. Оскільки змінні, задекларовані з, letє об'єктом блоку (де блок є кодом між фігурними дужками, наприкладif{} , for{}, function{}).

let змінні не піднімаються:

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

змінні з let не піднімаються:

console.log(letVar);

let letVar = 10;
// referenceError, the variable doesn't get hoisted

змінні з var do отримують:

console.log(varVar);

var varVar = 10;
// logs undefined, the variable gets hoisted

Глобальний let не приєднується до window:

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

var bar = 5;
let foo  = 10;

console.log(bar); // logs 5
console.log(foo); // logs 10

console.log(window.bar);  
// logs 5, variable added to window object

console.log(window.foo);
// logs undefined, variable not added to window object


Коли слід letвикористовувати понад var?

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


9

Також виявляється, що, принаймні, у Visual Studio 2015, TypeScript 1.5, "var" дозволяє кілька блоків одного і того ж імені змінної в блоці, а "нехай" - ні.

Це не призведе до помилки компіляції:

var x = 1;
var x = 2;

Це буде:

let x = 1;
let x = 2;

9

var - це змінна глобальна сфера (з можливістю підйому).

letі constє блоком області дії.

test.js

{
    let l = 'let';
    const c = 'const';
    var v = 'var';
    v2 = 'var 2';
}

console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined


8

При використанні let

letКлючове слово надає оголошення змінної в рамках якої - небудь блок (зазвичай є{ .. } пара) він міститься. Іншими словами, letнеявно викрадає обсяг будь-якого блоку для його оголошення змінної.

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

function a(){
    { // this is the Max Scope for let variable
        let x = 12;
    }
    console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined

При використанні var

var а змінні в ES5 мають області функцій, тобто змінні дійсні в межах функції, а не за межами самої функції.

varдоступ до змінних можна отримати в windowоб'єкті, оскільки до них не можна отримати глобальний доступ.

function a(){ // this is the Max Scope for var variable
    { 
        var x = 12;
    }
    console.log(x);
}
a(); // 12

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

Одного з найвідоміших питань щодо інтерв'ю щодо обсягу також може бути достатнім для точного використання letтаvar як нижче;

При використанні let

for (let i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 0 to 9, that is literally AWW!!!
        }, 
        100 * i);
}

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

При використанні var

for (var i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 10 times 10
        }, 
        100 * i);
}

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


7

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

var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error

Див. Розділ " Емуляція приватних інтерфейсів "


Чи можете ви детальніше пояснити, як вирази функцій негайно викликаних функцій не забезпечують захист коду let? (Я припускаю, що ви маєте на увазі IIFE з функцією "самонавіювання".)
Роберт Сімер

І чому ви ставите hiddenPropertyв конструкторі? Є лише один hiddenPropertyдля всіх екземплярів вашого "класу".
Роберт Сімер

6

У більшості основних слів,

for (let i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i not accessible ❌

for (var i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i accessible ✔️

Пісочниця для гри навколо ↓

Редагувати нехай проти вар


4

Деякі хаки з let:

1.

    let statistics = [16, 170, 10];
    let [age, height, grade] = statistics;

    console.log(height)

2.

    let x = 120,
    y = 12;
    [x, y] = [y, x];
    console.log(`x: ${x} y: ${y}`);

3.

    let node = {
                   type: "Identifier",
                   name: "foo"
               };

    let { type, name, value } = node;

    console.log(type);      // "Identifier"
    console.log(name);      // "foo"
    console.log(value);     // undefined

    let node = {
        type: "Identifier"
    };

    let { type: localType, name: localName = "bar" } = node;

    console.log(localType);     // "Identifier"
    console.log(localName);     // "bar"

Геттер і сетер з let:

let jar = {
    numberOfCookies: 10,
    get cookies() {
        return this.numberOfCookies;
    },
    set cookies(value) {
        this.numberOfCookies = value;
    }
};

console.log(jar.cookies)
jar.cookies = 7;

console.log(jar.cookies)

будь ласка, що це означає let { type, name, value } = node;? ви створюєте новий об’єкт із 3 типом властивостей / ім'ям / значенням та ініціалізуєте їх зі значеннями властивостей з вузла?
AlainIb

У прикладі 3 ви повторно оголошуєте вузол, який викликає виняток. Ці всі приклади теж прекрасно справляються з var.
Рехан Хайдер

4

нехай проти вар. Вся справа в обсязі .

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

Дивіться мій приклад нижче та зазначте, як змінна лев (нехай) по-різному діє в двох console.logs; він стає поза сферою дії у 2-й консолі.log.

var cat = "cat";
let dog = "dog";

var animals = () => {
    var giraffe = "giraffe";
    let lion = "lion";

    console.log(cat);  //will print 'cat'.
    console.log(dog);  //will print 'dog', because dog was declared outside this function (like var cat).

    console.log(giraffe); //will print 'giraffe'.
    console.log(lion); //will print 'lion', as lion is within scope.
}

console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).
console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.

4

ES6 представив два нові ключові слова ( дозвольте і const ), що чергуються з var .

Коли вам потрібно уповільнення рівня блоку, ви можете перейти з let і const замість var.

У таблиці нижче наведено різницю між var, let та const

введіть тут опис зображення


3

нехай є частиною es6. Ці функції пояснять різницю простим способом.

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
}

3

Нижче показано, як "нехай" і "вар" відрізняються в області застосування:

let gfoo = 123;
if (true) {
    let gfoo = 456;
}
console.log(gfoo); // 123

var hfoo = 123;
if (true) {
    var hfoo = 456;
}
console.log(hfoo); // 456

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

Тоді як hfoo, дефінітоване " varспочатку" знаходиться в глобальному масштабі , але знову ж таки, коли ми оголошуємо його всередині if clause, воно вважає глобальний обсяг hfoo, хоча для його оголошення знову використовувався var. І коли ми знову присвоюємо його значення, ми бачимо, що глобальний масштаб hfoo також впливає. Це головна відмінність.


2

Як зазначено вище:

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

Приклад1:

У обох моїх прикладах у мене є функція myfunc. myfuncмістить змінну, myvarрівну 10. У своєму першому прикладі я перевіряю, чи myvarдорівнює 10 ( myvar==10). Якщо так, я по-аганськи оголошую змінну myvar(зараз у мене є дві мінні змінні) за допомогою varключового слова та присвоюю їй нове значення (20). У наступному рядку я друкую його значення на моїй консолі. Після умовного блоку я знову надрукую значення myvarна своїй консолі. Якщо ви подивитеся на вихід myfunc, myvarзначення має рівне 20.

нехай ключове слово

Example2: У моєму другому прикладі замість використання varключового слова в моєму умовному блоці я оголошую myvarвикористання letключового слова. Тепер, коли я телефоную, myfunc я отримую два різні виходи: myvar=20і myvar=10.

Отже різниця дуже проста, тобто її сфера застосування.


3
Будь ласка, не публікуйте зображення коду, це вважається поганою практикою щодо SO, оскільки він не буде шукати для майбутніх користувачів (як і проблеми з доступністю). Крім того, ця відповідь нічого не додає, що інші відповіді ще не зверталися.
inostia

2

Я хочу зв’язати ці ключові слова з контекстом виконання, оскільки контекст виконання є важливим у всьому цьому. Контекст виконання має дві фази: фазу створення та фазу виконання. Крім того, кожен контекст виконання має змінне середовище та зовнішнє середовище (його лексичне середовище).

Під час фази створення контексту виконання var, let і const все ще зберігатиме свою змінну в пам'яті з невизначеним значенням у змінному середовищі заданого контексту виконання. Різниця полягає у фазі виконання. Якщо ви використовуєте посилання на змінну, визначену з var до того, як їй буде призначено значення, вона буде просто невизначеною. Виняток не буде піднято.

Однак ви не можете посилатися на змінну, оголошену let або const, поки вона не буде оголошена. Якщо ви спробуєте використати його до того, як він буде оголошений, виняток буде піднято під час фази виконання контексту виконання. Тепер ця змінна все ще залишиться в пам'яті, люб’язно надавши Фазу створення контексту виконання, але Двигун не дозволить вам використовувати її:

function a(){
    b;
    let b;
}
a();
> Uncaught ReferenceError: b is not defined

Якщо змінна, визначена з var, якщо Engine не може знайти змінну в змінному середовищі поточного контексту виконання, тоді вона підніметься вгору по ланцюгу областей (Зовнішнє середовище) і перевірить змінну Середовище зовнішнього середовища на змінну. Якщо він не зможе знайти його там, він продовжить пошук у Сфера застосування. Це не стосується дозволу та const.

Друга особливість let - це введення області блоку. Блоки визначаються фігурними дужками. Приклади включають функціональні блоки, якщо блоки, для блоків тощо. Коли ви оголошуєте змінну з пустим всередину блоку, змінна доступна лише всередині блоку. Насправді, кожного разу, коли блок запускається, наприклад, у циклі for for, він створюватиме нову змінну в пам'яті.

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

І, нарешті, коли мова йде про контекст виконання, змінні, визначені var, будуть приєднані до об'єкта "цей". У глобальному контексті виконання це буде віконний об’єкт у браузерах. Це не стосується дозволу чи const.


2

Я думаю, що терміни та більшість прикладів трохи непосильні. Основне питання, яке я мав особисто, з різницею - розуміння, що таке "Блок". У якийсь момент я зрозумів, що блоком будуть будь-які фігурні дужки, крім IFзаяви. відкриваюча дужка {функції або циклу визначатиме новий блок, все, що визначено letв ньому, буде недоступним після дужки, що закривається, }тієї ж речі (функції або циклу); Зважаючи на це, було легше зрозуміти:

let msg = "Hello World";

function doWork() { // msg will be available since it was defined above this opening bracket!
  let friends = 0;
  console.log(msg);

  // with VAR though:
  for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!
  console.log(iCount2);
  
    for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefined
  console.log(iCount1);
  
} // friends will no be available after this closing bracket!
doWork();
console.log(friends);


1

Тепер я думаю, що є кращим розміщення змінних до блоку операторів, використовуючи let:

function printnums()
{
    // i is not accessible here
    for(let i = 0; i <10; i+=)
    {
       console.log(i);
    }
    // i is not accessible here

    // j is accessible here
    for(var j = 0; j <10; j++)
    {
       console.log(j);
    }
    // j is accessible here
}

Я думаю, що люди почнуть використовувати пускати сюди після того, щоб вони мали аналогічні показники в JavaScript, як інші мови, Java, C # тощо.

Люди, які не мають чіткого розуміння щодо того, як скористатися JavaScript, раніше робили помилку.

Піднімання не підтримується використанням let.

При такому підході помилки, наявні в JavaScript, видаляються.

Дивіться ES6 в глибині: дозвольте і погодьтесь, щоб зрозуміти це краще.


Для глибшого розуміння на ньому перейдіть за посиланням - davidwalsh.name/for-and-against-let
swaraj patil

1

Ця стаття чітко визначає різницю між var, let та const

const - це сигнал про те, що ідентифікатор не буде перепризначений.

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

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

https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.