Вопрос #1614923

Проанализируйте JavaScript-кейс: for (var i=0;i<3;i++){ setTimeout(()=>console.log(i),100); } — почему вывод 3,3,3 и как добиться 0,1,2 без использования глобальных переменных

Ответы
1


Причина: переменная `var i` имеет функциональную (не блочную) область видимости. Цикл выполняется быстро и к моменту срабатывания таймаутов значение `i` уже равно \(\,3\,\). Замыкания в стрелочных функциях ссылаются на ту же переменную `i`, поэтому вывод получается `3, 3, 3`. Задержка таймаута — \(\,100\,\) мс — просто откладывает вызов колбеков до после завершения цикла.
Как получить `0, 1, 2` без глобальных переменных (несколько вариантов):
1) Использовать `let` в заголовке цикла (каждая итерация получает свою переменную):
```javascript
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
```
2) Замыкание через IIFE (немедленно вызываемая функция), захватив текущее значение:
```javascript
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(() => console.log(j), 100);
})(i);
}
```
3) Передать аргумент в `setTimeout` (доп. параметры передаются в callback):
```javascript
for (var i = 0; i < 3; i++) {
setTimeout((j) => console.log(j), 100, i);
}
```
4) Захват значения через `bind` (создаёт новую функцию с фиксированным аргументом):
```javascript
for (var i = 0; i < 3; i++) {
setTimeout(console.log.bind(null, i), 100);
}
```
Коротко: проблема — общая для всех итераций переменная `var`; решение — создать для каждой итерации отдельную переменную/значение (через `let`, замыкание/IIFE, аргументы `setTimeout` или `bind`).

Минимум 10 символов
Прямой эфир