В чем разница между «let» и «var»?

4545

ECMAScript 6 представил это letзаявление .

Я слышал, что она описывается как «локальная» переменная, но я все еще не совсем уверен, как она ведет себя иначе, чем varключевое слово.

В чем различия? Когда следует letиспользовать более var?

TM.
источник
105
ECMAScript является стандартом и letвключен в черновик 6-го издания и, скорее всего, будет в окончательной спецификации.
Ричард Айотт
5
См. Kangax.github.io/es5-compat-table/es6 для обновленной матрицы поддержки функций ES6 (включая let). На момент написания Firefox, Chrome и IE11 все это поддерживали (хотя я считаю, что реализация FF не совсем стандартна).
Нико Бернс
22
Долгое время я не знал, что переменные в цикле for были привязаны к функции, в которую они были заключены. Я помню, как выяснил это впервые, и подумал, что это очень глупо. Я действительно вижу некоторую силу, зная теперь, как они могут быть использованы по разным причинам и как в некоторых случаях вы можете использовать переменную в цикле for, а не ограничивать ее областью действия.
Эрик Бишард
1
Это очень хорошее чтение wesbos.com/javascript-scoping
onmyway133
1
Хорошо объясненный ответ здесь stackoverflow.com/a/43994458/5043867
Пардип Джейн

Ответы:

6102

Общие правила

Основное отличие заключается в правилах определения объема. Переменные, объявленные 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
ThinkingStiff
источник
23
Помните, что вы можете создать блок, когда захотите. function () {code; {let inBlock = 5; } код; };
средний Джо
177
Так является ли целью операторы let только для освобождения памяти, когда она не нужна в определенном блоке?
NoBugs
219
@ NoBugs, да, и рекомендуется, чтобы переменные существовали только там, где они нужны.
Бэтмен
67
letВыражение блока не let (variable declaration) statementявляется стандартным и будет удалено в будущем, bugzilla.mozilla.org/show_bug.cgi?id=1023609 .
Gajus
19
Так что я просто не могу вспомнить ни одного случая, когда использование var было бы полезным. Может ли кто-нибудь привести пример ситуации, когда предпочтительнее использовать var?
Луис Сиира
623

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/…
Джим Хунцикер
11
Действительно, это распространенная ошибка в Javascript, и теперь я понимаю, почему это letбыло бы действительно полезно. Установка прослушивателей событий в цикле больше не требует немедленного вызова выражения функции для локальной видимости iна каждой итерации.
Адриан Мойса
19
Использование «let» только отодвигает эту проблему. Таким образом, каждая итерация создает частную независимую область блока, но переменная «i» все еще может быть повреждена последующими изменениями внутри блока (при условии, что переменная итератора обычно не изменяется внутри блока, но другие объявленные переменные let внутри блока вполне могут быть) и любая функция , объявленной внутри блок может, при вызове, коррумпированное значение «я» для других функций , объявленным в блоке , потому что они делают один и тот же частный блок объем , следовательно , ту же ссылку на «я».
Гэри
199

Какая разница между 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известна только в первом цикле for, но не до и после. Тем не менее, наша переменная iизвестна во всей функции.

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


Безопасно ли использовать letсегодня?

Некоторые люди утверждают, что в будущем мы будем использовать ТОЛЬКО операторы let, а операторы var станут устаревшими. JavaScript гуру Кайл Симпсон написал очень сложную статью о том, почему он считает, что это не так .

Сегодня, однако, это определенно не так. На самом деле, нам нужно спросить себя, безопасно ли использовать это letутверждение. Ответ на этот вопрос зависит от вашей среды:

  • Если вы пишете код JavaScript на стороне сервера ( Node.js ), вы можете смело использовать это letутверждение.

  • Если вы пишете код JavaScript на стороне клиента и используете браузер (например, Traceur или babel-standalone ), вы можете смело использовать это letутверждение, однако ваш код, вероятно, будет не оптимальным с точки зрения производительности.

  • Если вы пишете код JavaScript на стороне клиента и используете транспортер на основе Node (например, скрипт оболочки traceur или Babel ), вы можете смело использовать это letутверждение. А поскольку ваш браузер будет знать только о передаваемом коде, недостатки производительности должны быть ограничены.

  • Если вы пишете код JavaScript на стороне клиента и не используете транспортер, вам следует подумать о поддержке браузера.

    Есть еще некоторые браузеры, которые вообще не поддерживают let:

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


Как отслеживать поддержку браузера

Обновленный обзор того, какие браузеры поддерживают letоператор на момент прочтения этого ответа, см. На этой Can I Useстранице .


(*) Глобальные и функциональные переменные могут быть инициализированы и использованы до того, как объявлены, потому что переменные JavaScript подняты .Это означает, что объявления всегда находятся на вершине области видимости.

(**) Переменные области видимости не подняты

Джон Слегерс
источник
14
относительно ответа v4: iIS известен везде в функциональном блоке! Он начинается как undefined(из-за подъема), пока вы не назначите значение! ps: letтакже поднимается (до верхней части содержащего его блока), но будет давать ReferenceErrorссылку, когда на него ссылаются в блоке перед первым присваиванием. (ps2: я парень вроде точки с запятой, но вам не нужна точка с запятой после блока). При этом, спасибо за добавление проверки реальности в отношении поддержки!
GitaarLAB
@GitaarLAB: Согласно сети разработчиков Mozilla : «В ECMAScript 2015 привязки let не подлежат перемещению переменных, что означает, что объявления let не перемещаются в верхнюю часть текущего контекста выполнения». - В любом случае, я сделал несколько улучшений в своем ответе, которые должны прояснить разницу в поведении подъема между letи var!
Джон Слегерс
1
Ваш ответ значительно улучшился (я тщательно проверил). Обратите внимание, что та же ссылка, на которую вы ссылались в своем комментарии, также гласит: «Переменная (let) находится в« временной мертвой зоне »с начала блока до обработки инициализации». Это означает, что «идентификатор» (текстовая строка «зарезервировано», чтобы указывать на «что-то») уже зарезервирован в соответствующей области, в противном случае он станет частью области root / host / window. Лично для меня «подъём» означает не что иное, как резервирование / привязка объявленных «идентификаторов» к их релевантной области; исключая их инициализацию / назначение / модифицируемость!
GitaarLAB
И .. + 1. Ссылка на статью Кайла Симпсона, на которую вы ссылаетесь, отлично читается, спасибо вам за это! Также ясно о «временной мертвой зоне», также известной как «TDZ». Я хотел бы добавить одну интересную вещь: я читал об MDN, letи constего рекомендовали использовать только тогда, когда вам действительно нужны их дополнительные функции , потому что принудительное выполнение / проверка этих дополнительных функций (таких как const только для записи) приводит к «большему количеству работы». '(и дополнительные узлы области видимости в дереве областей действия) для (текущего) механизма (ов) для принудительного применения / проверки / проверки / настройки.
GitaarLAB
1
Обратите внимание, что MDN говорит, что IE интерпретирует let правильно. Что он? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Катинка Хесселинк,
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 это просто набор слов, которые были зарезервированы на годы. Когда добавили mozilla, пусть это будет просто расширение mozilla, без каких-либо связанных с ним спецификаций. ES6 должен определять поведение для операторов let, но это произошло после того, как Mozilla ввела синтаксис. Помните, у moz также есть E4X, который полностью мертв и только moz.
olliej
9
В IE11 добавлена ​​поддержка let msdn.microsoft.com/en-us/library/ie/dn342892%28v=vs.85%29.aspx
eloyesp
112

В принятом ответе отсутствует точка:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined
Lcf.vs
источник
19
Принятый ответ НЕ объясняет этот момент в своем примере. Принятый ответ только продемонстрировал это в forинициализаторе цикла, резко сузив сферу применения ограничений let. Upvoted.
Джон Дэвис
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в циклах in, можно ссылаться только внутри этого цикла.

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переменная все еще имеет значение за пределами области действия цикла for (Block Scope), но let iпеременная не определена вне области действия цикла for.

"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);

vlio20
источник
2
Какой инструмент я смотрю здесь?
Бартон
20
Chrome devtools
vlio20
Как разработчик настольных апплетов для Cinnamon, я не сталкивался с такими блестящими инструментами.
Бартон
48

Есть некоторые тонкие различия - область letвидимости ведет себя больше как переменная область видимости в более или менее любых других языках.

Например, он распространяется на вмещающий блок, они не существуют до их объявления и т. д.

Однако стоит отметить, что letэто только часть более новых реализаций Javascript и имеет различную степень поддержки браузера .

olliej
источник
11
Стоит также отметить, что ECMAScript является стандартом и letвключен в черновик 6-го издания и, скорее всего, будет в окончательной спецификации.
Ричард Айотт
23
Это разница, которая составляет 3 года: D
olliej
4
Просто наткнулся на этот вопрос, и в 2012 году это все еще так, что поддерживают только браузеры Mozilla let. Safari, IE и Chome - нет.
псевдосавант
2
Идея случайного создания области частичного блока при аварии - это хороший момент, будьте осторожны, letне поднимайте, чтобы использовать переменную, letопределенную в верхней части вашего блока. Если у вас есть ifутверждение, которое состоит из нескольких строк кода, вы можете забыть, что не можете использовать эту переменную до тех пор, пока она не будет определена. БОЛЬШАЯ ТОЧКА !!!
Эрик Бишард
2
@EricB: да и нет: "В ECMAScript 2015 let будет поднята переменная в верхнюю часть блока. Однако ссылка на переменную в блоке до объявления переменной приводит к ReferenceError (мое примечание: вместо старого доброго undefined). переменная находится в «временной мертвой зоне» от начала блока до обработки объявления. " То же самое касается «операторов переключения, потому что есть только один базовый блок». Источник: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GitaarLAB
29

Основное отличие является сфера разницы, в то время как пусть может быть доступны только внутри сферы он объявлен, как в течение цикла, вар может быть доступен за пределами цикла, например. Из документации в 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

При использовании внутри блока let ограничивает область действия переменной этим блоком. Обратите внимание на разницу между 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;
    }

    Собственно, Per @Bergi, оба 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создайте новую лексическую среду с этими именами для a) выражения инициализатора b) каждой итерации (прежде всего для вычисления выражения приращения), здесь есть больше деталей .

zangw
источник
4
Да, они подняты, но ведут себя как будто не подняты из-за (барабанной дроби) временной мертвой зоны - очень драматичное имя для идентификатора, недоступного до тех пор, пока он не объявлен :-)
Drenai
Так пусть поднят, но недоступен? Чем это отличается от «не поднят»?
N-съел
Надеюсь, Брайан или Берги вернутся, чтобы ответить на это. Поднята ли декларация о разрешении, но не задание? Спасибо!
N-съел
1
@ N-ели, вот один пост Берги, может быть, вы можете найти ответ в нем.
Zangw
Интересно, что это даже называется подъем, когда дело доходит до аренды. Я понимаю, что технически механизм синтаксического анализа предварительно захватывает его, но для всех целей и задач программист должен обращаться с ним так, как будто он не существует. С другой стороны, использование var имеет значение для программиста.
N-съел
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.

abroz
источник
2
@aborz: также очень классный синтаксис анонимной функции во втором примере. Это то, к чему я привык в C #. Я кое-что узнал сегодня.
Бартон
Исправление: Технически, синтаксис функции Arrow описан здесь => developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Бартон
3
На самом деле, вам не нужно let value = i;. forОператор создает лексический блок.
Зубная щетка
18

Разница заключается в объеме переменных, объявленных с каждой.

На практике существует ряд полезных последствий разницы в области применения:

  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
mormegil
источник
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 is $ {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
это первый раз, когда я вижу, что кто-то ведет себя так, как будто желательно использовать переменные тени. нет, цель let не в том, чтобы включить теневое копирование
Джон Хаугеланд,
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переменная bar, объявленная с помощью 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 делать прибудут водрузил:

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» допускает несколько объявлений одного и того же имени переменной в блоке, а «let» - нет.

Это не сгенерирует ошибку компиляции:

var x = 1;
var x = 2;

Это будет:

let x = 1;
let x = 2;
RDoc
источник
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для каждой итерации цикла переменная находится в области видимости и имеет общую копию.

Анкур Сони
источник
8

В самых общих чертах,

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

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

⚡️ Песочница для игры ↓

Отредактируйте let vs 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вашем «классе» есть только один экземпляр.
Роберт Симер
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)
zloctb
источник
пожалуйста, что это значит let { type, name, value } = node;? Вы создаете новый объект с 3 свойствами тип / имя / значение и инициализируете их значениями свойств из узла?
AlainIb
В примере 3 вы повторно объявляете узел, который вызывает исключение. Все эти примеры тоже отлично работают var.
Рехан Хайдер
4

пусть является частью 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
}
Vipul Jain
источник
4

пусть против вар. Все дело в сфере .

Переменные var глобальны и доступны практически везде, а переменные пусть не глобальны и существуют только до тех пор, пока закрывающая скобка не убьет их.

Посмотрите мой пример ниже и обратите внимание, как переменная lion (let) действует по-разному в двух console.logs; это выходит из области видимости во втором console.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.
daCoda
источник
4

ES6 представил два новых ключевых слова ( let и const ), альтернативных var .

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

В таблице ниже приведены различия между var, let и const

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

Srikrushna
источник
3

Ниже показано, как «let» и «var» различаются по объему:

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ограничен до ближайшего окружающего блока , который может быть меньше функционального блока. Оба являются глобальными, если находятся вне какого-либо блока. Давайте посмотрим на пример:

Example1:

В обоих моих примерах у меня есть функция myfunc. myfuncсодержит переменную, myvarравную 10. В моем первом примере я проверяю, myvarравно ли равно 10 ( myvar==10). Если да, я объявляю переменную myvar(теперь у меня есть две переменные myvar), используя varключевое слово, и присваиваю ей новое значение (20). В следующей строке я печатаю его значение на моей консоли. После условного блока я снова печатаю значение myvarна моей консоли. Если вы посмотрите на вывод myfunc, myvarимеет значение, равное 20.

пусть ключевое слово

Пример 2: Во втором примере вместо использования varключевого слова в моем условном блоке я объявляю myvarиспользование letключевого слова. Теперь, когда я звоню, myfunc я получаю два разных выхода: myvar=20и myvar=10.

Таким образом, разница очень проста, т.е.

N Randhawa
источник
3
Пожалуйста, не публикуйте картинки кода, это считается плохой практикой в ​​SO, так как он не будет доступен для поиска для будущих пользователей (а также из-за проблем с доступностью). Кроме того, этот ответ не добавляет ничего, к чему другие ответы еще не обращались.
Иноастия
2

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

На этапе создания контекста выполнения var, let и const будут по-прежнему сохранять свою переменную в памяти с неопределенным значением в среде переменных данного контекста выполнения. Разница заключается в фазе исполнения. Если вы используете ссылку на переменную, определенную с помощью var, до того, как ей будет присвоено значение, она будет просто неопределенной. Никаких исключений не будет.

Однако вы не можете ссылаться на переменную, объявленную с помощью let или const, пока она не будет объявлена. Если вы попытаетесь использовать его до того, как он будет объявлен, тогда будет возникать исключительная ситуация на этапе выполнения контекста выполнения. Теперь переменная все еще будет в памяти, благодаря фазе создания контекста выполнения, но механизм не позволит вам использовать ее:

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

С переменной, определенной с помощью var, если Engine не может найти переменную в переменной среде текущего контекста выполнения, он поднимется по цепочке областей действия (внешняя среда) и проверит переменную среду внешней среды для переменной. Если он не может найти его там, он продолжит поиск в Scope Chain. Это не относится к let и const.

Вторая особенность let - это введение в область видимости блока. Блоки определяются фигурными скобками. Примеры включают в себя функциональные блоки, блоки if, для блоков и т. Д. Когда вы объявляете переменную с помощью let inside блока, переменная доступна только внутри блока. Фактически, каждый раз, когда блок запускается, например, в цикле for, он создает новую переменную в памяти.

ES6 также вводит ключевое слово const для объявления переменных. const также имеет ограниченную область видимости. Разница между let и const заключается в том, что переменные const должны быть объявлены с использованием инициализатора, иначе это вызовет ошибку.

И, наконец, когда дело доходит до контекста выполнения, переменные, определенные с помощью var, будут присоединены к объекту 'this'. В глобальном контексте выполнения это будет объект окна в браузерах. Это не относится к let или 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);

Dementic
источник
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
}

Я думаю, что люди начнут использовать let here после этого, чтобы у них была такая же область видимости в JavaScript, как и в других языках, Java, C # и т. Д.

Люди с неясным пониманием области видимости в JavaScript раньше делали ошибку.

Подъем не поддерживается с помощью let.

При таком подходе ошибки, присутствующие в JavaScript, удаляются.

Обратитесь к ES6 In Depth: пусть и const, чтобы понять это лучше.

Swaraj Patil
источник
Для углубленного понимания на нем см ссылку - davidwalsh.name/for-and-against-let
свараджа Патил
1

Эта статья четко определяет разницу между var, let и const

const является сигналом того, что идентификатор не будет переназначен.

let, является сигналом о том, что переменная может быть переназначена, например, счетчик в цикле или обмен значениями в алгоритме. Это также сигнализирует о том, что переменная будет использоваться только в блоке, в котором она определена, что не всегда является всей содержащей функцией.

varтеперь является самым слабым сигналом, доступным при определении переменной в JavaScript. Переменная может быть или не быть переназначена, и переменная может или не может использоваться для всей функции или просто для цели блока или цикла.

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

anandharshan
источник