Петли и затворы. Для и Var
Я нашел много тем, объясняющих эту проблему, о том, как я могу исправить следующий код с помощью var, как этот
http://conceptf1.blogspot.com/2013/11/javascript-closures.html или этот Закрытие JavaScript внутри циклов - простой практический пример.
Но я действительно не могу понять, почему он не работает при использовании var и работает при использовании let.
var funcs = [];
for (var i = 0; i < 3; i++) { // let create 3 functions
funcs[i] = function() { // and store them in funcs
console.log("My value: " + i); // each should log its value.
};
}
for (var j = 0; j < 3; j++) {
funcs[j](); // and now let run each one to see
}
// outputs 3 3 3
У меня действительно нет подсказки...
Ответы
Ответ 1
ES6 let
- это область блока, которая означает, что у нее есть собственная область внутри {}
, как и многие другие традиционные языки. Но в отличие от var
есть глобальная переменная в вашем коде.
В первом цикле for
function
присваивается func[i]
3 раза с конечным значением 3, но не выполняется. Если вы выполните функцию внутри первого loop
, вы получите ожидаемый результат, как будто:
var funcs = [];
for (var i = 0; i < 3; i++) { // let create 3 functions
funcs[i] = function() { // and store them in funcs
console.log("My value: " + i); // each should log its value.
};
funcs[i](); // execution of func
}
Ответ 2
Поскольку var
является областью действия функции (т.е. имеет объем окружения), тогда как let
и const
являются блочными областями - таким образом, они имеют свои собственные значения внутри каждого блока (будь то if
- или else
-блока или каждой итерации цикла, как в вашем случае). Переменные с блочной областью не определены вне блока. Переменные с функциональной областью остаются до конца функции.
Ваша переменная i
имеет функцию-область действия, что означает, что после завершения цикла все еще присутствует вне первого цикла и имеет значение 3
. Поэтому, как только вы вызываете функцию массива, она берет i
из верхней области (которая 3
) и выводит ее. Если вы использовали let
, например, вы получили бы новое связывание для каждой итерации, и ваше значение i
сохранит начальное значение объявления.
Изменить:
Поэтому для вывода последовательных значений вам нужно заменить var
на let
:
for (let i = 0; i < 3; i++) {
funcs[i] = function() {
// now `i` is bound to the scope & keeps its initial value
console.log("My value: " + i);
};
}
Ответ 3
В отличие от let
, var
выведен за пределы области цикла. Фактически, ваша переменная i
всегда будет равна последней итерации (которая в вашем примере равна 3). let
не имеет этой проблемы, потому что он не поднят.