2009-11-04 15 views
23

considerar, tales bucle:JavaScript variable de unión y el bucle

for(var it = 0; it < 2; it++) 
{ 
    setTimeout(function() { 
     alert(it); 
    }, 1); 
} 

La salida es:

=> 2 
=> 2 

me gustaría que fuera: 0, 1. Veo dos maneras de solucionarlo:

Solución n. ° 1.

Esta basada en el hecho de que podemos pasar datos a setTimeout.

for(var it = 0; it < 2; it++) 
{ 
    setTimeout(function(data) { 
     alert(data); 
    }, 1, it); 
} 

Solución # 2.

function foo(data) 
{ 
    setTimeout(function() { 
     alert(data); 
    }, 1); 
} 

for(var it = 0; it < 2; it++) 
{ 
    foo(it); 
} 

¿Hay otras alternativas?

Respuesta

42

En realidad, no nada más de las dos formas que se han propuesto, pero aquí es otra

for(var it = 0; it < 2; it++) 
{ 
    (function() { 
     var m = it; 
     setTimeout(function() { 
      alert(m); 
     }, 1); 
    })(); 
} 

En esencia, lo que necesita para capturar el valor de la variable en un cierre. Este método utiliza una función anónima invocada inmediatamente para capturar el valor de la variable externa it en una variable local m.

Aquí hay un Working Demo para jugar. añadir /editar a la URL para ver el código

+4

+1. Sin embargo, puede modificarlo ligeramente cambiando la firma del método a: 'function (m) {/ * code * /}) (it);' – Alan

+0

+1, pero ¿alguien puede explicarme por qué funciona? –

+1

@digorydoo La función declarada en el ciclo está envuelta entre paréntesis seguida de un conjunto de paréntesis que actúa para invocar inmediatamente la función. Dado que las variables tienen un alcance para la función en la que se declaran (o ámbito global si no se declara dentro de una función), el valor de 'it' en cada iteración se asigna a la variable' m' que se asigna a la función que se ejecuta inmediatamente. –

1

similares a la solución anterior, pero sí que invoca dentro de la función setTimeout

for(var it = 0; it < 2; it++) 
{ 
    setTimeout(function(cur) { 
     return function(){ 
      alert(cur); 
     }; 
    }(it), 1); 
} 
7

Con la palabra clave let puede evitar esto por completo:

for(let it = 0; it < 2; it++) 
{ 
    setTimeout(function() { 
     alert(it); 
    }, 1); 
} 
+0

pero no hay palabra clave llamada 'let' en javascript está en mecanografiado, creo –

1

similares a los de otras soluciones, pero en mi opinión más limpio:

for (var it = 0; it < 2; it++) { 
    // Capture the value of "it" for closure use 
    (function(it) { 
    setTimeout(function() { 
     alert(it); 
    }, 1); 
    // End variable captured code 
    })(it) 
} 

Esto mantiene el mismo nombre de variable para la captura, y lo hace para todo el ciclo, separándolo de la lógica de la configuración de tiempo de espera. Si desea agregar más lógica dentro del bloque, puede hacer eso trivialmente.

Lo único que no me gusta de la solución es la repetición de "eso" al final.

Cuestiones relacionadas