В ECMAScript 6 представлен оператор let
. Я слышал, что это описывается как "локальная" переменная, но я все еще не совсем уверен, как она ведет себя иначе, чем ключевое слово var
.
В чем отличия? Когда let
следует использовать var
?
Разница заключается в определении области. var
привязан к ближайшему функциональному блоку, а let
привязан к ближайшему закрывающему блоку, который может быть меньше функционального блока. Оба являются глобальными, если вне любого блока.
Кроме того, переменные, объявленные с помощью let
, недоступны, прежде чем они будут объявлены в их закрывающем блоке. Как видно из демонстрации, это вызовет исключение ReferenceError.
Демо:
var html = '';
write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible
try {
write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
write('globalLet: exception');
}
write('\nset variables');
var globalVar = 'globalVar';
let globalLet = 'globalLet';
write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);
function functionScoped() {
write('\n#### function ####');
write('\nfunctionVar: ' + functionVar); //undefined, but visible
try {
write('functionLet: ' + functionLet); //undefined, *not* visible
} catch (exception) {
write('functionLet: exception');
}
write('\nset variables');
var functionVar = 'functionVar';
let functionLet = 'functionLet';
write('\nfunctionVar: ' + functionVar);
write('functionLet: ' + functionLet);
}
function blockScoped() {
write('\n#### block ####');
write('\nblockVar: ' + blockVar); //undefined, but visible
try {
write('blockLet: ' + blockLet); //undefined, *not* visible
} catch (exception) {
write('blockLet: exception');
}
for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
write('\nblockVar: ' + blockVar); // visible here and whole function
};
for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
write('blockLet: ' + blockLet); // visible only here
};
write('\nblockVar: ' + blockVar);
try {
write('blockLet: ' + blockLet); //undefined, *not* visible
} catch (exception) {
write('blockLet: exception');
}
}
function write(line) {
html += (line ? line : '') + '<br />';
}
functionScoped();
blockScoped();
document.getElementById('results').innerHTML = html;
<pre id="results"></pre>
Они очень похожи, если использовать это вне функционального блока.
let me = 'go'; // globally scoped
var i = 'able'; // globally scoped
Однако глобальные переменные, определенные с помощью let
, не будут добавлены как свойства глобального объекта window
, подобного тем, которые определены с помощью var
.
console.log(window.me); // undefined
console.log(window.i); // 'able'
Они идентичны при использовании в этом функциональном блоке.
function ingWithinEstablishedParameters() {
let terOfRecommendation = 'awesome worker!'; //function block scoped
var sityCheerleading = 'go!'; //function block scoped
}
Вот разница. let
видна только в цикле for()
, а var
видна для всей функции.
function allyIlliterate() {
//tuce is *not* visible out here
for( let tuce = 0; tuce < 5; tuce++ ) {
//tuce is only visible in here (and in the for() parentheses)
//and there is a separate tuce variable for each iteration of the loop
}
//tuce is *not* visible out here
}
function byE40() {
//nish *is* visible out here
for( var nish = 0; nish < 5; nish++ ) {
//nish is visible to the whole function
}
//nish *is* visible out here
}
Предполагая строгий режим, var
позволит вам повторно объявить одну и ту же переменную в той же области. С другой стороны, let
не будет:
'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.
let
также можно использовать, чтобы избежать проблем с закрытием. Он связывает свежую ценность, а не сохраняет старую ссылку, как показано в примерах ниже.
for(var i = 1; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
В приведенном выше коде представлена классическая проблема с закрытием JavaScript. Ссылка на переменную i
хранится в закрытии обработчика кликов, а не фактическое значение i
.
Каждый обработчик одного клика будет ссылаться на один и тот же объект, потому что существует только один объект-счетчик, который содержит 6, поэтому вы получаете по шесть на каждый клик.
Общим решением является обернуть это анонимной функцией и передать i
в качестве аргумента. Эти проблемы также можно избежать, используя let
вместо var
, как показано ниже в коде.
DEMO (протестировано в Chrome и Firefox 50)
'use strict';
for(let i = 1; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
let
, но предупреждает «6» для всех кнопок. Есть ли у вас источник, говорящий, как let
должен себя вести?
Здесь объяснение ключевого слова let
с некоторыми примерами.
let работает очень похоже на var. Основное различие заключается в том, что область действия переменной var является всей охватывающей функцией
Эта таблица в Википедии показывает, какие браузеры поддерживают Javascript 1.7.
Обратите внимание, что поддерживаются только браузеры Mozilla и Chrome. IE, Safari и, возможно, другие нет.
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
сегодня?Некоторые люди утверждают, что в будущем мы будем использовать только инструкции let и что инструкции var станут устаревшими. JavaScript-гуру Кайл Симпсон написал очень продуманную статью о том, почему это не так.
Сегодня, однако, это определенно не так. На самом деле нам действительно нужно спросить себя, можно ли использовать оператор let
. Ответ на этот вопрос зависит от вашей среды:
Если вы пишете код на стороне сервера ( Node.js), вы можете безопасно использовать оператор let
.
Если вы пишете код JavaScript на стороне клиента и используете транспилер (например, Traceur), вы можете безопасно использовать оператор let
, однако ваш код, скорее всего, будет оптимальным в отношении производительности.
Если вы пишете код JavaScript на стороне клиента и не используете транспилер, вам необходимо рассмотреть поддержку браузера.
Сегодня, 8 июня 2018 года, есть еще некоторые браузеры, которые не поддерживают let
!
Для актуального обзора того, какие браузеры поддерживают оператор let
во время вашего чтения этого ответа, см. Эту страницу " Can я Use
.
(*) Глобальные и функционально скопированные переменные могут быть инициализированы и использованы до того, как они будут объявлены, поскольку переменные JavaScript будут подняты. Это означает, что объявления всегда находятся в верхней части области.
(**) Заблокированные переменные диапазона не поднимаются
i
известен везде в функциональном блоке! Он начинается как undefined
(из-за подъема), пока вы не назначите значение! ps: let
также поднимается (до верхней части содержащего его блока), но выдаст ReferenceError
когда на него ссылаются в блоке перед первым присваиванием. (ps2: я парень вроде точки с запятой, но после блока вам не нужна точка с запятой). Тем не менее, спасибо за добавление проверки реальности в отношении поддержки!
let
и var
!
В принятом ответе отсутствует точка:
{
let a = 123;
};
console.log(a); // ReferenceError: a is not defined
for
, резко сузив сферу применения ограничений let
. Upvoted.
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
-it в блочном пространстве и имеет 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
Вот пример разницы между двумя (поддержка только что началась для chrome):
Как вы можете видеть, переменная var j
по-прежнему имеет значение вне области цикла for (Block Scope), но переменная let i
undefined вне области цикла 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);
Есть некоторые тонкие отличия - let
scoping ведет себя больше, как область видимости переменных, в более или менее любых других языках.
например. Он привязан к закрывающему блоку. Они не существуют до их объявления и т.д.
Однако стоит отметить, что let
является лишь частью новых реализаций Javascript и имеет разную степень поддержки .
let
он включен в черновик 6-го издания и, скорее всего, будет в окончательной спецификации.
Переменная не поднимается
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) каждая итерация (предшествующая оценке выражения инкремента), более подробная информация здесь.
Основное различие заключается разница объема, в то время как пусть может быть доступны только в области видимости она объявлена, как и в течение цикла, вар может быть доступен за пределами цикла, например. Из документации в MDN (примеры также из MDN):
let позволяет вам объявлять переменные, которые ограничены в области действия блоком, оператором или выражением, в котором он используется. Это отличается от ключевого слова var, которое определяет переменную глобально или локально для всей функции независимо от области видимости блока.
Переменные, объявленные с помощью 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
Вот пример, чтобы добавить к тому, что уже написаны другие. Предположим, вы хотите создать массив функций 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 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 scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined
На этот раз i
восстанавливается на каждой итерации цикла for
. Каждая функция теперь сохраняет значение i
во время создания функции, а adderFunctions
ведет себя как ожидалось.
Теперь изображение смешивает два поведения, и вы, вероятно, увидите, почему не рекомендуется смешивать новые let
и const
со старыми var
в том же script. Это может привести к некоторому эффектно запутанному коду.
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 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
Не позволяйте этому случиться с вами. Используйте linter.
ПРИМЕЧАНИЕ.. Это пример обучения, призванный продемонстрировать поведение
var
/let
в циклах и закрытие функций, которые также будут легко понятны. Это был бы ужасный способ добавить числа. Но общая техника захвата данных при закрытии анонимных функций может встречаться в реальном мире в других контекстах. YMMV.
Разница заключается в scope переменных, объявленных с каждым.
На практике существует ряд полезных последствий разницы в области:
let
переменные видны только в ближайшем закрывающем блоке ({ ... }
).let
переменные используются только в строках кода, которые появляются после объявления переменной (даже если они подняты!).let
переменные не могут быть переопределены с помощью следующих var
или let
.let
не добавляются к глобальному объекту window
.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 5" пять раз:
i is 5
i is 5
i is 5
i is 5
i is 5
var
вместо let
, код эквивалентен: var i = 0; while (i < 5) { doSomethingLater(); i++; }
i
находится за пределами замыкания, и к тому времени, когда doSomethingLater()
выполняется, i
уже был увеличен в 5 раз, поэтому на выходе получается значение i is 5
раз. Используя let
, переменная i
находится внутри замыкания, поэтому каждый асинхронный вызов получает свою собственную копию i
вместо использования «глобальной» копии, созданной с помощью var
.
for
. Более точное преобразование, хотя и более сложное, является классическим for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(
i is $ {j} ), 125/*ms*/); })(i); }
который вводит «запись активации функции» для сохранения каждого значения i
с именем j
внутри функции.
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].
Могут отображаться следующие две функции:
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
}
Основное различие между 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
получает testVar
переменную foo, объявленную с помощью var
, все еще доступна вне оператора if
. Эта переменная foo
будет доступна везде в рамках функции testVar
.
переменные с let
:
Когда вторая функция testLet
переменная bar, объявленная с let
, доступна только внутри оператора if
. Поскольку переменные, объявленные с let
являются блочными (где блок является кодом между фигурными скобками, например if{}
, for{}
, function{}
).
let
переменные не поднимаются: Другое различие между var
и let
- переменные с объявленными, и let
их не поднимают. Пример - лучший способ проиллюстрировать это поведение:
переменные с let
not let
hoisted:
console.log(letVar);
let letVar = 10;
// referenceError, the variable doesn't get hoisted
переменные с var
do get hoist:
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
over var
всякий раз, когда вы можете, потому что он просто ограничен более конкретным. Это уменьшает потенциальные конфликты именования, которые могут возникать при работе с большим количеством переменных. var
можно использовать, если вы хотите, чтобы глобальная переменная явно была на объекте window
(всегда внимательно изучите, если это действительно необходимо).
Также представляется, что, по крайней мере, в Visual Studio 2015, TypeScript 1.5, "var" допускает несколько объявлений с одним и тем же именем переменной в блоке, а "let" - нет.
Это не приведет к ошибке компиляции:
var x = 1;
var x = 2;
Это будет:
let x = 1;
let x = 2;
Прямо сейчас вы почти никогда не будете использовать let
, потому что обычно не можете рассчитывать на то, что он полностью поддерживается в дикой природе.
Я знаю, что не тот ответ, который вы искали, но это, вероятно, самое важное. Если у вас ограниченное развертывание, где вы знаете, что каждый получает 1,7, то вы счастливый парень.
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
Если я читаю спецификацию прямо тогда 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
Ключевое слово let
присоединяет объявление переменной к какому-либо блоку (обычно a { .. }
), в котором он содержится. Другими словами, 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
для каждой итерации цикла переменная имеет область действия и имеет общую копию.
Некоторые хаки с 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 свойствами type / name / value и инициализируете их значениями свойств из узла?
var
.
let является частью 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
}
Как уже упоминалось выше:
Разница заключается в определении области.
var
распространяется до ближайшего функционального блока, иlet
распространяются до ближайшего заключающего блока, который может быть меньше, чем функциональный блок. Оба являются глобальными, если вне любого блока. Давайте посмотрим пример:
Example1:
В обоих моих примерах у меня есть функция myfunc
. myfunc
содержит переменную myvar
10. В моем первом примере я проверяю, равен ли myvar
10 (myvar==10
). Если да, я agian объявляю переменную myvar
(теперь у меня есть две переменные myvar), используя ключевое слово var
и присваиваю ему новое значение (20). В следующей строке я напечатаю его значение на моей консоли. После условного блока я снова распечатываю значение myvar
на моей консоли. Если вы посмотрите на выход myfunc
, myvar
имеет значение равное 20.
Пример2: В моем втором примере вместо использования ключевого слова var
в моем условном блоке объявляю myvar
используя ключевое слово let
. Теперь, когда я вызываю myfunc
я получаю два разных выхода: myvar=20
и myvar=10
.
Таким образом, разница очень проста, т.е. ее объем.
В этой статье четко определена разница между var, let и const
const
- это сигнал, что идентификатор не будет переназначен.
let
, является сигналом, что переменная может быть переназначена, например, счетчик в цикле или обмен значениями в алгоритме. Он также сигнализирует что переменная будет использоваться только в блоке, в котором она определена, которая не всегда является целой содержащей функцией.
var
теперь является самым слабым сигналом, доступным при определении переменной в JavaScript. Переменная может быть переназначена или не может быть переназначена, а переменная может использоваться или не использоваться для целой функции или просто для назначение блока или цикла.
https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b
Теперь я думаю, что лучше использовать область видимости переменных для блока операторов с помощью 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 after, чтобы они имели аналогичную область видимости в JavaScript, как и другие языки, Java, С# и т.д.
Люди, не имеющие четкого представления о области видимости в JavaScript, используемые для совершения ошибки ранее.
Подъем не поддерживается с помощью let
.
При таком подходе ошибки, возникающие в JavaScript, удаляются.
Обратитесь к ES6 In Depth: let и const, чтобы лучше понять его.
Раньше в JavaScript были только две области, то есть функциональные и глобальные. С ключевым словом "let
" JavaScript теперь ввел переменные block-level
.
Чтобы иметь полное понимание ключевого слова 'let', ES6: 'let ключевое слово для объявления переменной в JavaScript поможет.
let
позволяет вам объявить переменную, ограниченную по объему блоком (локальная переменная). Основное отличие состоит в том, что область действия переменной var - это вся включающая функция. Например, рассмотрим следующий пример использования let
vs. var
:
if (foo) {
let foo = 5; // foo has limited scope
console.log(true);
} else {
console.log(false)
}
// ReferenceError: foo is not defined
if (foo) {
var foo = 5;
console.log(true);
} else {
console.log(false)
}
// true, foo can be accessed in the global scope
ECMAScript 6 добавило еще одно ключевое слово, чтобы объявлять переменные, другие "const", кроме "let".
Основная цель введения "let" и "const" над "var" заключается в том, чтобы обладать областью охвата вместо традиционной лексической области. В этой статье объясняется очень кратковременная разница между "var" и "let" , а также обсуждается обсуждение "const" .
Посмотрите эту ссылку в MDN
let x = 1;
if (x === 1) {
let x = 2;
console.log(x);
// expected output: 2
}
console.log(x);
// expected output: 1
let
, хотя это сделало бы его дубликатом другого ответа.
let
вне if
определяет переменную x=1
. Оператор if
сработает (так как x===1 is true
. Теперь начинается сложная часть, которая также является основной причиной, по которой вам нужно отслеживать let
vs var
. Внутри if
он пытается установить x=2
, который в console.log(x)
будет печатать 2, ОДНАКО, x
"снаружи" в if все еще имеет значение 1
, поэтому другой console.log(x)
дает 1, так как значение x
"глобально "по-прежнему 1
Ответ не объясняет этого, поэтому не следует считать хорошим ответом по моему мнению.
полностью объяснил. Переменные ES2015 - Var, Let & Const
Вот хорошая ссылка. Объявления переменной Variables TypeScript: var, let, const → http://www.tutorialsteacher.com/typescript/typescript-variable
let
он включен в черновик 6-го издания и, скорее всего, будет в окончательной спецификации.