2010-05-17 16 views
19

Ich erwartete, dass der Code unten "0" und "1" warnt, aber es warnt zweimal "2". Ich verstehe den Grund nicht. Ich weiß nicht, ob es ein Problem von jQuery ist. Bitte helfen Sie mir auch Titel und Tags dieses Beitrags zu bearbeiten, wenn sie ungenau sind.Umfang der Variablen in JavaScript Callback-Funktionen

<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> 
+2

@chaos: rechts unter "Macht HTML nicht mit regex", denke ich. ;) – Tomalak

+2

* (nichts für ungut) * [JavaScript Closures for Dummies] (http://blog.morrisjohns.com/javascript_closures_for_dummies.html) Beispiel 5 –

+0

Es ist schwer, nur einen aus der Nähe auszuwählen: http://stackoverflow.com/ Fragen/1734749/ http: // Stapelüberlauf.com/Fragen/643.542/ http://stackoverflow.com/questions/1582634/ http://stackoverflow.com/questions/1331769/ http://stackoverflow.com/questions/1552941/ http://stackoverflow.com/questions/750486/ http://stackoverflow.com/questions/933343/ http://stackoverflow.com/questions/1579978/ http://stackoverflow.com/ Fragen/1413916/ http://StackOverflow.com/Questions/2808471/ – CMS

Antwort

38

Sie teilen die einzelnen i Variable unter all den Rückrufe.

Da Javascript-Verschlüsse Variablen als Referenz erfassen, verwenden die Rückrufe immer den aktuellen Wert i. Wenn jQuery die Callbacks nach der Ausführung der Schleife aufruft, ist i daher immer 2.

Sie müssen i als Parameter für eine separate Funktion referenzieren.

Zum Beispiel:

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

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

Auf diese Weise wird jeder Rückruf einen separaten Verschluss mit einem separaten i Parameter haben.

0

Es scheint, dass Sie eine Schließung innerhalb Ihrer Schleife erstellt haben Die Mozilla Developers Reference hat eine good section darüber.

1

In diesem Fall ist Ihre AJAX-Anfrage $.get abgeschlossen, nachdem die Schleife abgeschlossen wurde. Aus diesem Grund ist i die letzte Variable, auf die es gesetzt wird, wenn die Iterationen abgeschlossen sind, was 2 ist. Dies ist nur ein seltsames JavaScript-Problem und hat nichts mit jQuery zu tun.

Eine Sache, die Sie tun können, besteht darin, diese Aufrufe asynchron anzuordnen, sodass die Iteration anhält, bis die aktuelle AJAX-Anforderung abgeschlossen ist. Wenn Sie das nicht möchten, können Sie die Variable i in einer function Schließung in jeder Iteration erfassen.

Etwas wie folgt aus:

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

Alternative zu SLaks' Antwort

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

@RTF Nein, es ist das Gleiche, nur anders ausgedrückt. Außerdem sind solche Dinge sehr wahrscheinlich der letzte Ort, an dem Ihre Leistung den Bach runter geht, also verwenden Sie es, weil Sie es besser mögen, nicht weil Sie glauben, es könnte schneller sein. (Um ehrlich zu sein, ist es nicht * genau * das gleiche. Es erstellt ein zusätzliches Funktionsobjekt pro Schleifeniteration. Messen Sie den Leistungsunterschied und finden Sie heraus, ob Sie sich darum kümmern sollten.) – Tomalak

1

Eine alternative Lösung ist Ihr Rückruf zu nehmen und es buchstäblich eine benannte Funktion machen.

Warum sollte ich das tun?
Wenn eine Funktion etwas tut, bei dem eine Variable einen neuen Bereich einnehmen muss, dann ist es wahrscheinlich, dass die anonyme Funktion den Ausbruch einer neuen Funktion rechtfertigt. Dadurch wird auch sichergestellt, dass der Code nicht unnötig komplex wird, indem Sie Variablen kopieren oder Callbacks umbrechen müssen. Ihr Code bleibt einfach und beschreibend.

Beispiel:

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

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