Skip to main content

Цикл з var і setTimeout

Через дві речі одночасно:

  1. var - функціональна область видимості. У циклі for (var i = 0; i < 3; i++) { ... } створюється одна змінна i на всю функцію, а не нова на кожну ітерацію. Усі колбеки setTimeout "замикають" те саме значення i.
  2. setTimeout виконується пізніше. Колбеки потрапляють у чергу макрозадач і запускаються після того, як поточний JS-стек спорожніє. До моменту першого виклику таймера цикл уже завершено, і i має фінальне значення (наприклад, 3).

Симптом

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

Як виправити

Варіант 1 - let (блокова область видимості):

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

Варіант 2 - IIFE/замикання з передачею поточного i:

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

Варіант 3 - передати аргументом у setTimeout:

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

Варіант 4 - bind:

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

Коротко: var дає одну "спільну" змінну на весь цикл, а setTimeout запускається, коли цикл уже закінчено. Використовуйте let або ізолюйте значення через замикання/аргументи.

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

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

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