}
Почему выводит 5 пять раз, как это связано с области видимости и замыканиями, и какие разные способы исправления (ES5/ES6/функциональные) вы предложите

6 Ноя в 08:38
7 +7
0
Ответы
1
Коротко — потому что цикл использует переменную с функциональной областью видимости (`var`), замыкания сохраняют ссылку на эту одну переменную, а к моменту выполнения отложенных функций её значение стало (5)(5)(5). То есть все замыкания читают одно и то же итоговое значение.
Пример проблемы:
```js
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i); // выведет 5 пять раз
}, 0);
}
```
Почему так происходит (пояснение): `var i` — одна переменная в функции; каждая функция в `setTimeout` замыкает ссылку на эту переменную, а не её текущее значение. Когда таймауты выполняются, цикл уже завершён и `i === 5`, поэтому все выводы — (5)(5)(5).
Способы исправить
1) ES5 — IIFE (замкнуть текущее значение в параметре)
```js
for (var i = 0; i < 5; i++) {
(function (iCopy) {
setTimeout(function () {
console.log(iCopy);
}, 0);
})(i);
}
```
2) ES5 — bind или передача аргумента
```js
for (var i = 0; i < 5; i++) {
setTimeout(function (j) {
console.log(j);
}.bind(null, i), 0);
}
// или
for (var i = 0; i < 5; i++) {
setTimeout((function (j) {
return function () { console.log(j); };
})(i), 0);
}
```
3) ES6 — блочная область видимости `let` (самый простой)
```js
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 0); // выведет 0,1,2,3,4
}
```
В ES6 `let` создаёт новое связывание для каждой итерации цикла, поэтому каждое замыкание видит своё значение.
4) Функциональный стиль — методы коллекций / фабрики
```js
[0,1,2,3,4].forEach(function (i) {
setTimeout(() => console.log(i), 0);
});
// или фабрика колбэков
function makeLogger(x) {
return function () { console.log(x); };
}
for (var i = 0; i < 5; i++) {
setTimeout(makeLogger(i), 0);
}
```
Краткая сводка:
- Проблема — замыкания захватывают ссылку на одну `var`-переменную; результат меняется к моменту выполнения. Результат — повторный вывод (5)(5)(5).
- Решения — создать отдельное лексическое связывание для каждой итерации (IIFE, `.bind`, фабрика) или использовать блоковую область `let`/`const` (ES6) или функциональные методы (`forEach`, фабрики).
6 Ноя в 09:09
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир