Приведён следующий JavaScript-фрагмент: var funcs=[]; for(var i=0;if()); Объясните, почему вывод будет 3,3,3, как это связано с областью видимости var/let и замыканиями, и предложите несколько способов исправить ожидаемое поведение (0,1,2)

31 Авг в 04:12
22 +1
0
Ответы
1
Почему получается 3, 3, 33,\,3,\,33,3,3
- В исходном коде переменная `i` объявлена через `var`, а `var` имеет функциональную (не блочную) область видимости. Поэтому внутри цикла существует одна общая переменная `i`.
- Функции, которые вы пушите в массив, создают замыкания, и они сохраняют ссылку на эту общую переменную `i`, а не копию её значения.
- После завершения цикла значение `i` равно 333. При вызове каждой функции они читают текущее значение общей `i`, поэтому вывод будет 3, 3, 33,\,3,\,33,3,3.
Связь с var/let и замыканиями
- `var` — одна переменная для всей функции/глобала; замыкания захватывают ссылку на неё.
- `let` (и `const`) — блочная область видимости; в заголовке `for` для каждой итерации создаётся новое связывание `i`, поэтому каждое замыкание получает свою независимую копию значения.
Способы исправить (чтобы получить 0, 1, 20,\,1,\,20,1,2)
1) Использовать `let` в цикле:
for (let i = 000; i < 333; i++) {
funcs.push(function(){ console.log(i); });
}
результат: 0, 1, 20,\,1,\,20,1,2
2) Захват значения через IIFE (немедленно вызываемую функцию):
for (var i = 000; i < 333; i++) {
(function(x){
funcs.push(function(){ console.log(x); });
})(i);
}
результат: 0, 1, 20,\,1,\,20,1,2
3) Фабрика функций (явная копия значения в параметре):
function makeLogger(x){ return function(){ console.log(x); }; }
for (var i = 000; i < 333; i++) {
funcs.push(makeLogger(i));
}
результат: 0, 1, 20,\,1,\,20,1,2
4) Использовать привязку `bind` (значение фиксируется при вызове bind):
for (var i = 000; i < 333; i++) {
funcs.push(console.log.bind(console, i));
}
результат: 0, 1, 20,\,1,\,20,1,2
5) Создать массив/итерировать с помощью методов, где индекс доступен (ES6):
Array.from({ length: 333 }, (_, i) => funcs.push(() => console.log(i)));
результат: 0, 1, 20,\,1,\,20,1,2
Короткая рекомендация: если нужно простое поведение — используйте `let` в цикле (пункт 1).
31 Авг в 04:21
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир