Помилка з var у замиканнях і циклі
Класика: у циклі з var усі колбеки "бачать" одну й ту саму змінну i (у var функціональна область видимості). Коли колбеки виконуються, i вже дорівнює кінцевому значенню циклу.
Проблема
javascript
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// 3, 3, 3Надійні способи виправити
- Використати
let/const(ES6+) - у циклу з'являється нове лексичне зв'язування на кожну ітерацію.
javascript
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // 0, 1, 2
}- IIFE (самовиклична функція) - "заморожуємо" поточне значення
i.
javascript
for (var i = 0; i < 3; i++) {
(function(iCopy) {
setTimeout(() => console.log(iCopy), 0);
})(i);
}- Передача аргументів колбеку через обгортку/фабрику
javascript
function makeLogger(x) {
return () => console.log(x);
}
for (var i = 0; i < 3; i++) {
setTimeout(makeLogger(i), 0);
}- Методи масиву (
forEach,map) - параметр колбеку вже "пов'язаний" зі значенням.
javascript
[0,1,2].forEach(i => setTimeout(() => console.log(i), 0));- Передача аргументу в
setTimeout(підтримується в браузерах/Node):
javascript
for (var i = 0; i < 3; i++) {
setTimeout(x => console.log(x), 0, i);
}Короткий чек-лист
- Типово використовуй
let/constу циклах - це найпростіший і найбезпечніший шлях. - Якщо з якихось причин потрібен
var, зафіксуй значення через IIFE/фабрику/передачу аргументу. - Пам'ятай: замикання захоплюють змінну, а не її миттєве значення - у
varвона одна на весь цикл.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.