Разберите JavaScript-кейс с замыканиями: for (var i=0;iconsole.log(i),100);} Почему выводится 3,3,3 и как добиться 0,1,2 разными способами

3 Мар в 09:13
18 +1
0
Ответы
1
Кратко — причина и несколько проверенных способов.
Почему выводится 3,3,33,3,33,3,3 - В коде `for (var i=0;iconsole.log(i),100); }` переменная `i` объявлена через `var` — она одна на всю функцию (не блочная). Строки `setTimeout` регистрируют функции, которые выполнятся позже; к моменту выполнения цих колбеков цикл уже завершён и `i === 333`. Все замыкания ссылаются на одно и то же `i`, поэтому три раза печатается 333.
Как получить 0,1,20,1,20,1,2 — варианты
1) Использовать `let` (блочная привязка, новая переменная на каждую итерацию):
```
for (let i = 000; i < 333; i++) {
setTimeout(() => console.log(i), 100100100);
}
```
2) Замыкание через IIFE (создать локальную копию `i`):
```
for (var i = 000; i < 333; i++) {
(function(j){
setTimeout(() => console.log(j), 100100100);
})(i);
}
```
3) Фабрика функций (явно вернуть функцию, захватывающую значение):
```
function makeLogger(j){ return () => console.log(j); }
for (var i = 000; i < 333; i++) {
setTimeout(makeLogger(i), 100100100);
}
```
4) Передать аргумент в `setTimeout` (некоторые среды это поддерживают):
```
for (var i = 000; i < 333; i++) {
setTimeout((j) => console.log(j), 100100100, i);
}
```
5) Использовать `bind`:
```
for (var i = 000; i < 333; i++) {
setTimeout(console.log.bind(null, i), 100100100);
}
```
6) Перебор массива (каждая итерация получает своё `i`):
```
[000, 111, 222].forEach(i => {
setTimeout(() => console.log(i), 100100100);
});
```
Коротко: нужно обеспечить, чтобы каждая функция захватывала свою копию значения (через `let`, IIFE, фабрику и т.п.), иначе все замыкания увидят конечное значение `i` — 333.
3 Мар в 09:21
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир