Основное различие - разность областей, в то время как let может быть доступна только в пределах области, которую она объявила, например, для цикла for, например, для доступа к var вне цикла. Из документации в MDN (примеры также из MDN):
let позволяет вам объявлять переменные, которые ограничены по объему блоку, выражению или выражению, на которых Это использовано. Это не похоже на ключевое слово var, которое определяет переменную глобально или локально для целой функции независимо от области блока.
Переменные, объявленные let, имеют в качестве области действия блок, в котором они определены, а также в любых содержащихся подблоках. Таким образом, пусть работает очень похоже на var. Основное различие заключается в том, что область действия переменной var является всей охватывающей функцией:
blockquote>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, не создать свойство на глобальном объекте. Например:
blockquote>var x = 'global'; let y = 'global'; console.log(this.x); // "global" console.log(this.y); // undefined
При использовании внутри блока, ограничивает область видимости переменной этим блоком. Обратите внимание на разницу между var, область видимости которой находится внутри функции, где она объявлена.
blockquote>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
Является ли это просто синтаксическим сахаром для ES6?
blockquote>Нет, это больше, чем синтаксический сахар.
Как это работает?
blockquote>Если вы используете это ключевое слово
let
в инструкцииfor
, он проверит, какие имена он связывает, а затем
- создает новую лексическую среду с этими именами для a) выражение инициализатора b) каждая итерация (ранее для оценки выражения инкремента)
- копирует значения из всех переменных с этими именами из одной в следующую среду
Ваш оператор цикла
for (var i = 0; i < 10; i++) { process.nextTick(_ => console.log(i)) }
desugars на простой// omitting braces when they don't introduce a block var i; i = 0; if (i < 10) process.nextTick(_ => console.log(i)) i++; if (i < 10) process.nextTick(_ => console.log(i)) i++; …
, в то время как
for (let i = 0; i < 10; i++) { process.nextTick(_ => console.log(i)) }
делает «desugar» более сложным// using braces to explicitly denote block scopes, // using indentation for control flow { let i; i = 0; __status = {i}; } { let {i} = __status; if (i < 10) process.nextTick(_ => console.log(i)) __status = {i}; } { let {i} = __status; i++; if (i < 10) process.nextTick(_ => console.log(i)) __status = {i}; } { let {i} = __status; i++; …
let
вводит определение области и эквивалентную привязку, так же как функции создают область с закрытием. Я считаю, что соответствующий раздел спецификации 13.2.1 , где в заметке упоминается, что let
объявления являются частью LexicalBinding и оба живут в пределах Лексической среды. Раздел 13.2.2 утверждает, что объявления var
прикреплены к переменной VariableEnvironment, а не к LexicalBinding.
Объяснение MDN также поддерживает это, заявив, что:
Он работает, связывая ноль или более переменных в лексической области одного блока кода
blockquote>, предполагая, что переменные связаны с блок, который меняет каждую итерацию, требующую нового LexicalBinding (я считаю, а не 100% на эту точку), а не окружающая лексическая среда или переменная среда, которая была бы постоянной на время вызова.
Короче , при использовании
let
замыкание находится в теле цикла, и переменная различается каждый раз, поэтому его необходимо снова захватить. При использованииvar
переменная находится в окружающей функции, поэтому нет необходимости повторно закрывать, и одна и та же ссылка передается на каждую итерацию.Адаптация вашего примера для запуска в браузере:
// prints '10' 10 times for (var i = 0; i < 10; i++) { setTimeout(_ => console.log('var', i), 0); } // prints '0' through '9' for (let i = 0; i < 10; i++) { setTimeout(_ => console.log('let', i), 0); }
, безусловно, показывает, что последние печатают каждое значение. Если вы посмотрите на то, как Вавилон перебирает это, он производит:
for (var i = 0; i < 10; i++) { setTimeout(function(_) { return console.log(i); }, 0); } var _loop = function(_i) { setTimeout(function(_) { return console.log(_i); }, 0); }; // prints '0' through '9' for (var _i = 0; _i < 10; _i++) { _loop(_i); }
Предполагая, что Вавилон довольно совместим, что соответствует моей интерпретации спецификация