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