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