Разберите следующий код на JavaScript и объясните, почему он выводит неожиданные значения в цикле — предложите корректный вариант: for (var i = 0; i console.log(i), 100); }
Проблема: переменная `var` имеет функциональную (не блочную) область видимости. Колбэки в `setTimeout` замыкают одну и ту же переменную `i`. К моменту срабатывания таймеров (после ~100100100 мс) цикл завершён и i=3i = 3i=3, поэтому вы получаете три раза значение 333. Оригинал выводит: 3,3,33, 3, 33,3,3. Исправления (корректные варианты): 1) Использовать `let` (каждая итерация получает свою привязку): for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); } 2) Замыкание через IIFE (явно сохранить значение в параметре): for (var i = 0; i < 3; i++) { (function(j) { setTimeout(function() { console.log(j); }, 100); })(i); } 3) Передать аргумент в `setTimeout` (поддерживается в современных средах): for (var i = 0; i < 3; i++) { setTimeout((j) => console.log(j), 100, i); } 4) Использовать `bind`: for (var i = 0; i < 3; i++) { setTimeout(console.log.bind(null, i), 100); } Любой из этих вариантов выведет: 0,1,20, 1, 20,1,2.
Оригинал выводит: 3,3,33, 3, 33,3,3.
Исправления (корректные варианты):
1) Использовать `let` (каждая итерация получает свою привязку):
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
2) Замыкание через IIFE (явно сохранить значение в параметре):
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(function() { console.log(j); }, 100);
})(i);
}
3) Передать аргумент в `setTimeout` (поддерживается в современных средах):
for (var i = 0; i < 3; i++) {
setTimeout((j) => console.log(j), 100, i);
}
4) Использовать `bind`:
for (var i = 0; i < 3; i++) {
setTimeout(console.log.bind(null, i), 100);
}
Любой из этих вариантов выведет: 0,1,20, 1, 20,1,2.