Какова область видимости переменной Javascript в цикле for()?
Ознакомьтесь со следующим фрагментом кода HTML/Javascript:
<html>
<head>
<script type="text/javascript">
var alerts = [];
for(var i = 0; i < 3; i++) {
alerts.push(function() { document.write(i + ', '); });
}
for (var j = 0; j < 3; j++) {
(alerts[j])();
}
for (var i = 0; i < 3; i++) {
(alerts[i])();
}
</script>
</head><body></body></html>
Выводится:
3, 3, 3, 0, 1, 2
чего я не ожидал - ожидал выход 0, 1, 2, 0, 1, 2,
I (неправильно) предположил, что анонимная функция, вставляемая в массив, будет вести себя как замыкание, фиксируя значение i
, которое назначается при создании функции, но на самом деле появляется, что i
ведет себя как глобальная переменная.
Может ли кто-нибудь объяснить, что происходит с областью i
в этом примере кода, и почему анонимная функция не фиксирует ее значение?
Ответы
Ответ 1
В Javasript единственной "интересной" лексической границей области является тело функции. Все, что объявлено в какой-либо функции (ну, где-нибудь, кроме другой вложенной функции!), Находится в той же области. Есть также некоторые странные вещи о том, как интерпретации деклараций.
Ваша анонимная функция действует как закрытие, но каждая созданная функция будет использовать один и тот же "i". Я использую трюк, чтобы добавить еще один уровень функции:
for (var i = 0; i < whatever; i++) {
(function(idaho) {
whatever(function() { alert("my own private " + idaho); });
})(i);
}
В какой-то точке мы надеемся, что все браузеры будут поддерживать новый оператор let, который является более коротким и менее странным способом сделать в основном то же самое.
Ответ 2
Область - это функция, в которой определена переменная (кроме нее нет, поэтому она является глобальной).
Анонимная функция, с которой вы проходите, обращается к переменной, определенной в родительской (снова глобальной) области.
Вам нужно фактическое закрытие.
alerts.push(
function (foo) {
return function() {
document.write(foo + ', ');
}
}(i)
);