2010-05-17 14 views
19

Esperaba que el código a continuación alertara "0" y "1", pero alerta "2" dos veces. No entiendo la razón. No sé si es un problema de jQuery. Además, ayúdame a editar el título y las etiquetas de esta publicación si son inexactos.alcance de las variables en las funciones de devolución de llamada de 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: Justo debajo de "No hagas HTML con expresiones regulares", supongo. ;) – Tomalak

+2

* (sin ofender) * [JavaScript Closures for Dummies] (http://blog.morrisjohns.com/javascript_closures_for_dummies.html) Ejemplo 5 –

+0

Es difícil elegir solo uno para cerrar: http://stackoverflow.com/ preguntas/1734749/ http: // stackoverflow.com/preguntas/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/ preguntas/1413916/ http://stackoverflow.com/questions/2808471/ – CMS

Respuesta

38

Estás compartiendo la única i variables entre todas las devoluciones de llamada.

Como los cierres de Javascript capturan las variables por referencia, las devoluciones de llamada siempre usarán el valor actual de i. Por lo tanto, cuando jQuery llama a las devoluciones de llamada una vez que se ejecuta el bucle, i siempre será 2.

Debe hacer referencia al i como el parámetro para una función separada.

Por ejemplo:

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

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

De esta manera, cada uno de devolución de llamada tendrá un cierre separado con un i parámetro independiente.

0

Parece que ha creado un cierre dentro de su ciclo La Referencia de Desarrolladores de Mozilla tiene un good section acerca de esto.

1

Lo que está ocurriendo aquí es que su solicitud AJAX $.get se está completando después de que el ciclo se haya completado. Debido a esto, i termina siendo la variable final que se establece cuando las iteraciones se completan, siendo 2. Esto es solo un extraño error de JavaScript, y no tiene nada que ver con jQuery.

Una cosa que puede hacer es poner en cola estas llamadas de forma asincrónica, por lo que la iteración se detiene hasta que se completa la solicitud AJAX actual. Si no quiere hacer eso, puede capturar la variable i en un cierre function en cada iteración.

Algo como esto:

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

alternativos para contestar SLaks'

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

@RTF No, es la misma cosa, simplemente expresan de forma diferente. Además, este tipo de cosas es muy probable que el último lugar donde su rendimiento va por el desagüe, a fin de utilizarlo porque te gusta mejor, no porque usted cree que podría ser más rápido. (Para ser absolutamente honesto, no es * exactamente * la misma. Se crea un objeto función extra por iteración del bucle. Medir la diferencia de rendimiento y averiguar si usted debe cuidar.) – Tomalak

1

Una solución alternativa a esto es para tomar su devolución de llamada y, literalmente, lo convierten en una función llamada.

¿Por qué querría hacer esto?
Si una función está haciendo algo en donde una variable necesita tomar un nuevo alcance, entonces es probable que la función anónima exija una nueva función. Esto también asegurará que no se introduzca complejidad adicional en su código al tener que copiar variables o envolver devoluciones de llamadas. Tu código seguirá siendo simple y autodescriptivo.

Ejemplo:

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

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