Циклы и замыкания
Читаю книгу "You don't know JavaScript". Тема - замыкания.
for (var i=1; i<=5; i++) {
setTimeout( function timer(){
console.log( i );
}, i*1000 );
}
Код выше, по словам автора, выведет 6 раз шестерку, ибо
Все функции обратного вызова функции timeout запускаются прямо после завершения цикла
Проблема была решена следующим образом:
for (var i=1; i<=5; i++) {
(function(j){
setTimeout( function timer(){
console.log( j );
}, j*1000 );
})( i );
}
Аргумент анонимной функции j перенял ссылку на глобальное i. Это ок. Но вот следующее меня очень смущает:
for (let i=1; i<=5; i++) {
setTimeout( function timer(){
console.log( i );
}, i*1000 );
}
Осознаю разницу между let и var. С let переменная i видима только для своего блока. В данном случае для цикла. В то время, как var глобален. С ним можно получить i вне блока. Но почему в последнем примере setTimeout не сработал после цикла, как было озвучено выше. Ведь вся разница с самым первым примером кода и последним в доступе i вне блока for. Я думал, что замыканием внутри анонимной функции и решается проблема запуска setTimeout после цикла, а не во время него. Так почему при условии глобального i setTimeout запустился после цикла, а при локальной i setTimeout запускается при каждой итерации цикла?
Ответы (1 шт):
setTimeout в любом случае асинхронный и всегда запустится позже цикла. Разница в том, что с let эта переменная не одна, а создается другая новая на каждый шаг цикла, и функция в таймауте каждый раз обращается к разным переменным, а не к одной изменяемой.
Цитата из https://learn.javascript.ru/let-const:
При использовании в цикле, для каждой итерации создаётся своя переменная.
Переменная var – одна на все итерации цикла и видна даже после цикла:
for(var i=0; i<10; i++) { /* … */ }
alert(i); // 10 С переменной let – всё по-другому.
Каждому повторению цикла соответствует своя независимая переменная let. Если внутри цикла есть вложенные объявления функций, то в замыкании каждой будет та переменная, которая была при соответствующей итерации.