Подтвердить что ты не робот

Объем переменных в функциях обратного вызова JavaScript

Я ожидал, что код ниже будет предупреждать "0" и "1", но он предупреждает "2" дважды. Я не понимаю причину. Не знаю, является ли проблема jQuery. Также, пожалуйста, помогите мне изменить заголовок и теги этого сообщения, если они неточны.

<html>
    <head>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script type="text/javascript">
            $(function() {
                for (var i=0; i<2; i++) {
                    $.get('http://www.google.com/', function() {
                        alert(i);
                    });
                }
            });
        </script>
    </head>
    <body>
    </body>
</html>
4b9b3361

Ответ 1

Вы делитесь единственной переменной i среди всех обратных вызовов.

Поскольку Javascript закрывает захват переменных по ссылке, обратные вызовы всегда будут использовать текущее значение i. Поэтому, когда jQuery вызывает обратные вызовы после выполнения цикла, i всегда будет 2.

Вам нужно указать i как параметр для отдельной функции.

Например:

function sendRequest(i) {
    $.get('http://www.google.com/', function() {
        alert(i);
    });
}

for (var i = 0; i < 2; i++) {
    sendRequest(i);
}

Таким образом, каждый обратный вызов будет иметь отдельное закрытие с отдельным параметром i.

Ответ 2

Альтернатива ответу SLaks

$(function() {
    for (var i=0; i<2; i++) {
        $.get('http://www.google.com/', function(i) {
            return function() { alert(i); }
        }(i));
    }
});

Ответ 3

Что происходит здесь, ваш запрос AJAX $.get завершается после завершения цикла. Из-за этого i заканчивается как конечная переменная, которую он установил, когда итерации завершены, будучи 2. Это просто странный JavaScript-код и не имеет ничего общего с jQuery.

Одна вещь, которую вы можете сделать, заключается в асинхронной очереди этих вызовов, так что итерация останавливается до тех пор, пока не будет завершен текущий запрос AJAX. Если вы не хотите этого делать, вы можете захватить переменную i в закрытии function на каждой итерации.

Что-то вроде этого:

for ( var i = 0; i < 2; i++ )
    (function(iter){
        $.get('http://www.google.com/', function(){
            alert( iter );
        });
    })(i); // Capture i

Ответ 4

Альтернативное решение для этого - принять ваш обратный вызов и буквально сделать его именованной функцией.

Почему я хочу это сделать?
Если функция выполняет что-то, где переменная должна обладать новой областью, то, скорее всего, анонимная функция требует выхода в новую функцию. Это также гарантирует, что дополнительная сложность не будет введена в ваш код, если вам придется копировать переменные или завершать обратные вызовы. Вы код остаетесь простым и самоописательным.

Пример:

function getGoogleAndAlertIfSuccess(attemptNumber) {
    $.get('http://www.google.com/', function() {
        alert(attemptNumber);
    });
}

function testGoogle() {
    for (var i=0; i<2; i++) {
        getGoogleAndAlertIfSuccess(i);
    }
}

Ответ 5

Похоже, что вы создали закрытие внутри цикла. Справочник разработчиков Mozilla имеет хороший раздел об этом.