← Все вопросы

Почему в цикле for с var и setTimeout всегда печатается одно и то же число?

Задан 13 месяцев назад841 просмотров3 ответа
15

Запускаю такой код и ожидаю 0,1,2,3,4, а в консоли пять раз подряд 5. Что не так?

for (var i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 100);
}

3 ответа

27
✓ Принятый ответ — помог автору

Тут два эффекта сразу: замыкание + область видимости var.

var i — одна-единственная переменная на весь цикл (она функциональной области видимости, не блочной). Все пять колбэков setTimeout запоминают ссылку на одну и ту же i. Колбэки выполняются позже, когда цикл уже закончился и i стало равно 5. Поэтому печатается пять раз 5.

Самое простое решение — заменить var на let:

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

let в цикле for создаёт новую переменную на каждой итерации, и каждый колбэк замыкается на свою копию i. Старый способ (до ES6) — обернуть в IIFE и передать i параметром, но сейчас let решает всё в одну строку.

Олег Зайцев именно «новая i на каждую итерацию у let» — вот ключ, который всё объясняет · 13 месяцев назад
Оксана Крылова то же самое всплывает в forEach vs for на собесах · 13 месяцев назад
10

Замени var на let. С var переменная одна на весь цикл, и к моменту срабатывания таймеров она уже равна 5. let создаёт свою i на каждой итерации.

5

Замени var на let.

Ваш ответ

Войдите, чтобы ответить на вопрос.
Поддержать проект