В этой статье мы рассмотрим заглушку JavaScript и попытаемся понять, как она работает в деталях.
Постановка задачи
Что будет на выходе для этой заглушки?
const func = () => { for (var i = 1; i < 5; i++) { setTimeout(() => console.log(i), 1000); } } func();
Отвечать
Распространенный неправильный ответ
Самый распространенный ответ, который мы получаем от новичков:
Вывод будет 1, 2, 3, 4
Но, очевидно, это неправильно, все не так просто, как кажется.
Правильный ответ
Вывод будет 5, 5, 5, 5
Живая работа
Давайте посмотрим, как это работает в браузере.
Чтобы проверить в браузере,
- Я создал html-файл и добавил кнопку, по нажатию которой мы можем вызвать функцию.
- Просто чтобы различать каждый console.log, я добавил текущую временную метку Date.
- И добавил отладчик в console.log для проверки стека вызовов и закрытия.
Обсудить, почему так происходит?
Задав этот простой вопрос, интервьюер затронул сложные темы JavaScript, такие как цикл событий, замыкание и подъем.
Разберемся, что происходит во время исполнения.
- Прежде всего следует отметить, что мы используем ключевое слово
var
, которое поднимет переменнуюi
в родительскую область, и она будет сохранена в куче. - Во-вторых, мы вызываем webAPI
setTimeout
внутри цикла for. Таким образом, все четыре функцииconsole.log
будут помещены в Очередь обратного вызова. - Как только выполнение цикла for завершено (он достигает критического состояния, которое в нашем случае равно 5), он удаляется из стека вызовов, а затем цикл событий вводит все четыре
console.log
из Очереди обратного вызова. - Но в этот момент переменная
i
присутствует в куче и ее значение равно 5. Вот почему все четыре console.log регистрируют 5 в браузере.
Как мы можем это исправить?
Мы можем исправить это, просто изменив var
на let
. Это сделает область видимости блока переменной i
.
Если вы хотите узнать больше об этих сложных темах в деталях, прочтите эти замечательные статьи на Medium.