Разберите пример на JavaScript с асинхронностью: function foo() { for (var i=0;iconsole.log(i),100); } } — что выведется и почему; как исправить, если нужно вывести 0,1,2?
Выведется три раза 333. Почему: в цикле переменная объявлена через `var`, она имеет функциональную (не блочную) область видимости, и все три таймаута замыкают одну и ту же переменную `i`. К моменту исполнения колбэков (примерно через 100100100 мс) цикл уже завершён и i=3i = 3i=3, поэтому `console.log(i)` выведёт 333 три раза. Как исправить, чтобы получить 0,1,20,1,20,1,2: 1) Использовать блочную переменную `let` в цикле: ```js function foo() { for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); } } ``` 2) Захватить текущее значение через IIFE (функцию-замыкание): ```js function foo() { for (var i = 0; i < 3; i++) { (function(j) { setTimeout(() => console.log(j), 100); })(i); } } ``` 3) Передать значение в колбэк через `bind` или дополнительные аргументы `setTimeout`: ```js // bind function foo() { for (var i = 0; i < 3; i++) { setTimeout(console.log.bind(null, i), 100); } } // или дополнительные аргументы (работает в браузере и Node) function foo() { for (var i = 0; i < 3; i++) { setTimeout((v) => console.log(v), 100, i); } } ``` Любой из этих подходов даст вывод 0, 1, 20,\,1,\,20,1,2.
Почему: в цикле переменная объявлена через `var`, она имеет функциональную (не блочную) область видимости, и все три таймаута замыкают одну и ту же переменную `i`. К моменту исполнения колбэков (примерно через 100100100 мс) цикл уже завершён и i=3i = 3i=3, поэтому `console.log(i)` выведёт 333 три раза.
Как исправить, чтобы получить 0,1,20,1,20,1,2:
1) Использовать блочную переменную `let` в цикле:
```js
function foo() {
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
}
```
2) Захватить текущее значение через IIFE (функцию-замыкание):
```js
function foo() {
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(() => console.log(j), 100);
})(i);
}
}
```
3) Передать значение в колбэк через `bind` или дополнительные аргументы `setTimeout`:
```js
// bind
function foo() {
for (var i = 0; i < 3; i++) {
setTimeout(console.log.bind(null, i), 100);
}
}
// или дополнительные аргументы (работает в браузере и Node)
function foo() {
for (var i = 0; i < 3; i++) {
setTimeout((v) => console.log(v), 100, i);
}
}
```
Любой из этих подходов даст вывод 0, 1, 20,\,1,\,20,1,2.