Проверяет понимание области видимости var, замыканий и асинхронного поведения setTimeout в цикле, что часто встречается на собеседованиях по JavaScript.
Когда вы объявляете переменную через var внутри цикла for, она не создаётся заново на каждой итерации. Вместо этого существует одна переменная в области видимости функции (или глобальной), которая просто перезаписывается. Колбэки, переданные в setTimeout, захватывают ссылку на эту единственную переменную, а не её значение на момент вызова.
Цикл выполняется синхронно и очень быстро, а колбэки setTimeout попадают в очередь задач и выполняются только после того, как стек вызовов опустеет. К этому моменту цикл уже завершён, и переменная i равна конечному значению. Все колбэки читают одно и то же актуальное значение.
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 3, 3, 3
}, 0);
}
Нужно создать новую область видимости для каждой итерации, чтобы каждый колбэк захватывал свою собственную переменную. Это можно сделать несколькими способами.
i как аргумент, создавая локальную копию.bind.// Вариант 1: IIFE
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(function() {
console.log(j); // 0, 1, 2
}, 0);
})(i);
}
// Вариант 2: функция-обёртка
function logLater(j) {
setTimeout(function() { console.log(j); }, 0);
}
for (var i = 0; i < 3; i++) {
logLater(i);
}
Понимание этого поведения важно при работе с асинхронным кодом, обработчиками событий и любыми колбэками внутри циклов. Даже если вы используете let, полезно знать, почему он решает проблему: let создаёт новую привязку на каждой итерации, и каждый колбэк замыкается на свою переменную.
Итог: используйте IIFE или функцию-обёртку, когда нужно зафиксировать значение переменной var на момент итерации; в современном коде предпочтительнее let, который делает это автоматически.
Frontend developer
Ментор по Frontend
Полное сопровождение до оффера — без дорогих курсов, с оплатой после трудоустройства
Записаться на консультацию