Skip to main content

Помилка з var у замиканнях і циклі

Класика: у циклі з var усі колбеки "бачать" одну й ту саму змінну ivar функціональна область видимості). Коли колбеки виконуються, i вже дорівнює кінцевому значенню циклу.

Проблема

javascript
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // 3, 3, 3

Надійні способи виправити

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

Короткий чек-лист

  • Типово використовуй let/const у циклах - це найпростіший і найбезпечніший шлях.
  • Якщо з якихось причин потрібен var, зафіксуй значення через IIFE/фабрику/передачу аргументу.
  • Пам'ятай: замикання захоплюють змінну, а не її миттєве значення - у var вона одна на весь цикл.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.