Какова область действия переменной Javascript, объявленной в цикле for ()? - PullRequest
10 голосов
/ 29 апреля 2010

Ознакомьтесь со следующим фрагментом кода 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 в этом примере кода, и почему анонимная функция не захватывает ее значение?

Ответы [ 2 ]

8 голосов
/ 29 апреля 2010

Область действия - это функция, в которой определена переменная (за исключением того, что ее нет, поэтому она является глобальной).

Передаваемая вами анонимная функция обращается к переменной, определенной в родительской функции (снова глобально) область действия.

Вам необходимо фактическое закрытие.

alerts.push(
    function (foo) { 
        return function() { 
            document.write(foo + ', ');

        }
    }(i)
);
6 голосов
/ 29 апреля 2010

В Javasript единственной "интересной" границей лексической области видимости является тело функции. Все, что объявлено где-либо в функции (ну, в любом месте, кроме другой вложенной функции!) Находится в той же области видимости. Есть также некоторые странные вещи о способе интерпретации объявлений.

Ваша анонимная функция действует как замыкание, но каждая созданная функция будет иметь одно и то же "i". Уловка, которую я использую, состоит в том, чтобы добавить еще один слой функции:

for (var i = 0; i < whatever; i++) {
  (function(idaho) {
    whatever(function() { alert("my own private " + idaho); });
  })(i);
}

Надеемся, что в какой-то момент все браузеры будут поддерживать новый оператор let, который является более коротким и менее странным способом сделать в основном то же самое.

...