JavaScript

Вопрос по JS. Пожалуйста скажите почему код дает 6 пять раз. Почему не 1,2,3,4,5 .Очень запуталась от setTimeout.

for (var i = 1; i <= 5; ++i) {
setTimeout(function(){
console.log(i);
}, 1000);
}
Еще не понятно то, что при обявлении переменную i с let, ответ 1,2,3,4,5 . Да понимаю что у let block scope, а у var function scope, но честно не понимаю почему тут так. Ведь в каждом шагу цикла i меняет значение, и дает ее setTimout-у независимо от того как обявлена i (с let или с var). Заранее спасибо за ответы.
Просто замени var на let.

Всё дело в том, что у тебя ВСЕ функции, передаваемые в setTimeout, захватывают ОДНУ переменную i. И выводят значение этой переменной, которое после завершения цикла равно 6.

Если же заменить var на let, то на каждой итерации цикла создаётся новая переменная i - со своим уникальным значением. И каждая функция, передаваемая в setTimeout, захватывает свою переменную со своим значением.

Либо можно обернуть setTimeout в функцию:

for (var i = 1; i <= 5; ++i) {
(function(x) { setTimeout(function() { console.log(x); }, 100); })(i);
}

В этом случае будет захватываться не i, а x, создаваемая на каждом вызове функции.
Studnikov Denis
Studnikov Denis
50 250
Лучший ответ
Толян Бойко Спасибо большое. Все понятно, только непоняла почему с let нормально. "на каждой итерации цикла создаётся новая переменная i - со своим уникальным значением" - как же так? Разве при цикле i не создается один раз а потом просто увеличивается значение? Немного не поняла с let.
Если нужен практический пример счетчика, то никаких 1,2,3,4,5 в вашем случае и не получится, получится просто 6.
Чтобы последовательно вывести 1,2,3,4,5 нужно делать так:
var inter = setInterval(foo, 1000);
i = 1;
function foo () {
console.log(i);
i++;
if (i == 6) clearInterval(inter)
}
попроробуте заменить ++i
на i++
Evgeny Vagner
Evgeny Vagner
77 048
Толян Бойко То же самое и с i++.
Всё просто. В цикле задаются пять функций, которые выведут значение переменной i через секунду после установки таймаута. А через секунду цикл уже будет завершен.

По завершении цикла значение переменной i в результате инкремента достигнет 6. Так как условие i <= 5 не соблюдено, то цикл завершается, и в итоге имеем i = 6. А затем срабатывают наши таймауты, видят i = 6, выводят.
Алексей Пегаев
Алексей Пегаев
78 049
Сергей Леонидович Христолюбов Для автора: дело не в секундной задержке (с нулевой будет то же самое), а в асинхронности вызова той функции, что передается аргументом в setTimeout. Сначала выполняется синхронный код, и только затем - очередь асинхронных вызовов.
Толян Бойко Спасибо большое. Все понятно, но только почему и с let не так?
Потомучто если переменная объявлена с вар она глобальная и когда настанет время таймаута функция заберёт значение i а цикл к тому моменту уже докрутится до шести
let это вобще временная переменная живущая в блоке - там все просто работает какую переменную ближе нашел ту и взял
Maksim Salukin
Maksim Salukin
59 848
nотому что вы сначала увеличиваете счетчик ++i а потом выполняете тело цикла
Толян Бойко То же самое и с i++.