Проанализируйте следующий JavaScript-кусок: for (var i = 0; i

12 Окт 2025 в 14:18
16 +1
0
Ответы
1

Результат этого кода — три строки с числом 3 (в консоли будет напечатано по очереди 3, 3, 3).

Почему так происходит (коротко):

var i — функциональная (не блочная) переменная. В цикле создаётся одна переменная i, которую все три функции в setTimeout «замыкают» (они хранят ссылку на одну и ту же переменную).setTimeout с задержкой 100 ms выполняет колбэки уже после завершения цикла. К тому моменту цикл закончился и i стало равно 3. Поэтому каждая из функций при вызове читает текущее значение i = 3.

Пояснение с точки зрения событийного цикла: setTimeout планирует колбэк в очередь событий; выполнение колбэков произойдёт позже, когда стек свободен — а к тому времени переменная i уже изменилась.

Три разных способа исправить (с примерами, плюс преимущества/недостатки):

1) Использовать let (ES6), блочная область видимости

for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 100);
}

Почему работает: при каждой итерации для i создаётся новая блочная привязка, колбэк «замыкает» своё собственное i. Выведет 0, 1, 2.

Плюсы: лаконично, современно, понятное поведение.
Минусы: требует ES6 (в старых окружениях без транспиляции — несовместимо).

2) Создать замыкание через IIFE (подходит для старого JS)

for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(function() {
console.log(j);
}, 100);
})(i);
}

Почему работает: IIFE получает текущее значение i в параметр j и создаёт новую область, которую замыкает колбэк. Выведет 0, 1, 2.

Плюсы: работает в старых средах без ES6.
Минусы: более многословно, может выглядеть менее современно.

3) Передать значение в setTimeout (или использовать bind)
Вариант A — дополнительные аргументы setTimeout:

for (var i = 0; i < 3; i++) {
setTimeout(function(j) {
console.log(j);
}, 100, i);
}

Вариант B — bind:

for (var i = 0; i < 3; i++) {
setTimeout(console.log.bind(null, i), 100);
}

Почему работает: setTimeout позволяет передать аргументы в колбэк (или bind фиксирует аргумент) — передаётся текущее значение i, которое становится независимым от переменной i. Выведет 0, 1, 2.

Плюсы: коротко, явно фиксирует значение.
Минусы: передача дополнительных аргументов setTimeout исторически поддерживается большинством сред, но может выглядеть необычно; bind может менять контекст/параметры (в некоторых случаях не подходит, если нужен специфичный this).

Короткая заметка: аналогично let сработает и const (в for-of/for цикле const даёт новую привязку на каждую итерацию, но значение не может быть переназначено в теле итерации).

Вывод: в современных проектах самый простой и читаемый способ — использовать let (или const), в старых — IIFE или передачу аргументов/ bind.

12 Окт 2025 в 15:33
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир