Причина: переменная `i` объявлена через `var` — она имеет функциональную область видимости, поэтому все функции-обратного вызова захватывают одну и ту же переменную `i`. К моменту выполнения `setTimeout` цикл уже завершён и `i == arr.length`, поэтому в консоль выводится это значение (например, если `arr.length == 3`, вывод будет `3, 3, 3`). Формально: при условии цикла `i=0;i<arr.length;i++i = 0; i < arr.length; i++i=0;i<arr.length;i++` все замыкания видят одно и то же `iii`. Варианты исправления (минимум два): 1) Использовать блочную переменную `let` в цикле (каждая итерация получает свою копию `i`): function foo(arr){ for (let i = 0; i < arr.length; i++){ setTimeout(function(){ console.log(i); }, 0); } } 2) Захватить текущее значение `i` через IIFE: function foo(arr){ for (var i = 0; i < arr.length; i++){ (function(i){ setTimeout(function(){ console.log(i); }, 0); })(i); } } Дополнительно (ещё два простых способа): 3) Передать значение `i` как аргумент в `setTimeout` (поддерживается в среде браузера/Node): function foo(arr){ for (var i = 0; i < arr.length; i++){ setTimeout(function(i){ console.log(i); }, 0, i); } } 4) Использовать `forEach`, где индекс — параметр функции (внутри уже блоковая область для каждого вызова): function foo(arr){ arr.forEach(function(_, i){ setTimeout(function(){ console.log(i); }, 0); }); } Любой из первых двух способов решит проблему; вариант с `let` — самый простой и читаемый.
Варианты исправления (минимум два):
1) Использовать блочную переменную `let` в цикле (каждая итерация получает свою копию `i`):
function foo(arr){
for (let i = 0; i < arr.length; i++){
setTimeout(function(){
console.log(i);
}, 0);
}
}
2) Захватить текущее значение `i` через IIFE:
function foo(arr){
for (var i = 0; i < arr.length; i++){
(function(i){
setTimeout(function(){
console.log(i);
}, 0);
})(i);
}
}
Дополнительно (ещё два простых способа):
3) Передать значение `i` как аргумент в `setTimeout` (поддерживается в среде браузера/Node):
function foo(arr){
for (var i = 0; i < arr.length; i++){
setTimeout(function(i){
console.log(i);
}, 0, i);
}
}
4) Использовать `forEach`, где индекс — параметр функции (внутри уже блоковая область для каждого вызова):
function foo(arr){
arr.forEach(function(_, i){
setTimeout(function(){
console.log(i);
}, 0);
});
}
Любой из первых двух способов решит проблему; вариант с `let` — самый простой и читаемый.