В языке программирования показан фрагмент на JavaScript: for (var i=0; iconsole.log(i),100); } Объясните поведение кода, предложите несколько способов получить вывод 0,1,2,3,4 и обсудите различия между var, let и const в контексте замыканий

13 Мар в 09:30
21 +1
0
Ответы
1
Коротко о поведении фрагмента:
- Переменная объявлена через `var`, она имеет функциональную область видимости и одна общая привязка `i` для всех итераций. Таймауты выполнятся после завершения цикла, когда `i` стала равной 555. Поэтому в консоль выведется пять раз значение 555.
Примеры способов получить вывод 0,1,2,3,40, 1, 2, 3, 40,1,2,3,4:
1) Использовать `let` в заголовке цикла (каждая итерация получает свою привязку):
for (let i=000; i<555; i++){ setTimeout(()=>console.log(i), 100100100); }
2) Создать замыкание через IIFE (функцию, немедленно вызванную с текущим значением):
for (var i=000; i<555; i++){
(function(j){
setTimeout(()=>console.log(j), 100100100);
})(i);
}
3) Скопировать значение в блоковую переменную внутри тела цикла:
for (var i=000; i<555; i++){
let j = i;
setTimeout(()=>console.log(j), 100100100);
}
4) Передать аргумент в `setTimeout` (в средах, где поддерживается):
for (var i=000; i<555; i++){
setTimeout(function(n){ console.log(n); }, 100100100, i);
}
(или кратко: setTimeout(console.log, 100100100, i) — иногда бывают нюансы с `this` у `console.log`.)
Различия `var`, `let`, `const` в контексте замыканий:
- `var`: функциональная (или глобальная) область видимости, не имеет блочной привязки; цикл `for(var i=...)` создаёт одну переменную `i`, которую все замыкания читают/изменяют — типичная причина «все таймауты печатают одно и то же значение».
- `let`: блочная область видимости; для заголовка `for (let i=...)` спецификация ECMAScript создаёт новую привязку `i` для каждой итерации, поэтому замыкания захватывают разные значения (ожидаемый результат).
- `const`: тоже блочная область видимости и неизменяемая привязка (нельзя переназначить). Для обычного инкрементного `for` использовать `const i` нельзя (ошибка), но для конструкций типа `for (const x of arr)` полезна как блочная неизменяемая привязка. Как и `let`, для `for`-итераций блоковая семантика обеспечивает корректные замыкания.
- Ещё: `let/const` имеют TDZ (temporal dead zone) до момента инициализации, `var` — поднимается (hoisting) с начальным значением `undefined`.
Вывод: для простого исправления предпочтителен `let` в заголовке цикла; альтернативы — замыкание через IIFE, копирование в `let` внутри цикла или передача аргумента в `setTimeout`.
13 Мар в 10:17
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир