2010-05-17 9 views
19

Je m'attendais à ce que le code ci-dessous alerte "0" et "1", mais il alerte deux fois "2". Je ne comprends pas la raison. Je ne sais pas si c'est un problème de jQuery. Aussi, s'il vous plaît aidez-moi à modifier le titre et les balises de ce post si elles sont inexactes.étendue des variables dans les fonctions de rappel JavaScript

<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: juste en-dessous "Ne pas faire avec HTML regex", je suppose. ;) – Tomalak

+2

* (pas d'infraction) * [Fermetures JavaScript pour les nuls] (http://blog.morrisjohns.com/javascript_closures_for_dummies.html) Exemple 5 –

+0

Il est difficile de choisir un seul pour fermer: http://stackoverflow.com/ questions/1734749/ http: // stackoverflow.com/questions/643542/ 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/ questions/1413916/ http://stackoverflow.com/questions/2808471/ – CMS

Répondre

38

Vous partagez la variable i unique parmi tous les callbacks. Comme les fermetures Javascript capturent les variables par référence, les rappels utiliseront toujours la valeur actuelle i. Par conséquent, lorsque jQuery appelle les rappels après l'exécution de la boucle, i sera toujours 2.

Vous devez faire référence à i comme paramètre à une fonction distincte.

Par exemple:

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

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

De cette façon, chaque rappel aura une fermeture séparée avec un paramètre i séparé.

0

Il semble que vous ayez créé une fermeture à l'intérieur de votre boucle. La Référence Mozilla Developers a un good section à ce propos.

1

Ce qui se passe ici est que votre requête AJAX $.get se termine une fois la boucle terminée. Pour cette raison, i finit par être la variable finale à laquelle il est assigné lorsque les itérations se terminent, étant 2. Ceci est juste un étrange getcha JavaScript, et n'a rien à voir avec jQuery. Une chose que vous pouvez faire est de mettre ces appels en file d'attente de façon asynchrone afin que l'itération s'arrête jusqu'à ce que la requête AJAX en cours se termine. Si vous ne voulez pas faire cela, vous pouvez capturer la variable i dans une fermeture function à chaque itération.

Quelque chose comme ceci:

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

Alternative à la réponse de SLaks

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

@RTF Non, c'est la même chose, juste exprimée différemment. En outre, des choses comme celle-ci sont très probablement le dernier endroit où votre performance tombe à l'eau, alors utilisez-le parce que vous l'aimez mieux, pas parce que vous croyez que cela pourrait être plus rapide. (Pour être tout à fait honnête, ce n'est pas * exactement * la même chose.Il crée un objet fonction supplémentaire par itération de boucle.Mesurez la différence de performance et de savoir si vous devez vous en soucier.) – Tomalak

1

Une solution alternative à cela est de prendre votre rappel et faire littéralement une fonction nommée.

Pourquoi voudrais-je faire cela?
Si une fonction fait quelque chose où une variable doit prendre une nouvelle portée, il est probable que la fonction anonyme justifie une nouvelle fonction. Cela assurera également que la complexité supplémentaire n'est pas introduite dans votre code en copiant des variables ou en renvoyant des rappels. Votre code restera simple et auto-descriptif.

Exemple:

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

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