С var
у вас есть область видимости функции, и только один общий обязательный для всех ваших итераций цикла - то есть i
в каждом SetTimeout обратного вызова означает то же переменная, которая наконец равно 6 после цикла итерация заканчивается.
С let
у вас есть блок сферы и при использовании в цикле for
вы получите новый обязательный для каждой итерации - т.е. i
в каждом SetTimeout обратного вызова означает другую переменную, каждый из которых имеет различное значение : первый равен 0, следующий 1 и т.д.
Так что это:
(function timer() {
for (let i = 0; i <= 5; i++) {
setTimeout(function clog() { console.log(i); }, i * 1000);
}
})();
эквивалентно этому, используя только вар:
(function timer() {
for (var j = 0; j <= 5; j++) {
(function() {
var i = j;
setTimeout(function clog() { console.log(i); }, i * 1000);
}());
}
})();
Использование непосредственно вызываемого выражения функции для использования функции scope аналогично тому, как область видимости блока работает в примере с let
.
Это может быть записано короче без использования имени j
, но, возможно, не будет столь же ясно:
(function timer() {
for (var i = 0; i <= 5; i++) {
(function (i) {
setTimeout(function clog() { console.log(i); }, i * 1000);
}(i));
}
})();
И еще короче со стрелками функции:
(() => {
for (var i = 0; i <= 5; i++) {
(i => setTimeout(() => console.log(i), i * 1000))(i);
}
})();
(Но если вы можете используйте функции стрелок, нет оснований для использования var
.)
Вот как Babel.js переводит ваш пример с помощью let
работать в средах, где let
не доступен:
"use strict";
(function timer() {
var _loop = function (i) {
setTimeout(function clog() {
console.log(i);
}, i * 1000);
};
for (var i = 0; i <= 5; i++) {
_loop(i);
}
})();
Благодаря Michael Geary за размещение ссылки на Babel.js в комментариях. См. Ссылку в комментарии для демонстрации в реальном времени, где вы можете изменить что-либо в коде и посмотреть, что перевод происходит сразу. Интересно посмотреть, как можно перевести другие функции ES6.
См. Здесь http://stackoverflow.com/questions/762011/javascript-let-keyword-vs-var-keyword – eithed
Стоит отметить, что существует разница между старой версией Mozilla 'let' и новой ES2015 версия. Однако, для специфики этого вопроса, обманщик отвечает на это просто отлично. –
На мой взгляд, это не дубликат. Каждый раз, когда кто-то спрашивает о let или var, мы не можем указать на них очень общий ответ. Это специально задает вопрос о setTimeout(), который создает «замыкание в цикле» - общий сценарий проблемы с подъемом var - ответ и пример ниже не указаны в связанном дублированном принятом ответе – Ryan