Considere tal 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 formas de solucionarlo:

Solución # 1.

Esta basado 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?

30
alex2k8 4 nov. 2009 a las 23:20

4 respuestas

La mejor respuesta

Realmente no hay nada más que las dos formas que ha propuesto, pero aquí hay otra

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

Esencialmente, necesita capturar el valor 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 una Demostración de trabajo para jugar. agregue / edit a la URL para ver el código

44
Russ Cam 9 jun. 2011 a las 21:19

Similar a las 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 del tiempo de espera. Si desea agregar más lógica dentro del bloque, puede hacerlo trivialmente.

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

1
Eivind Eklund 1 sep. 2016 a las 10:09

Similar a la solución anterior pero auto invocado dentro de la función setTimeout

for(var it = 0; it < 2; it++)
{
    setTimeout(function(cur) {
        return function(){
           alert(cur);
        };
     }(it), 1);
 }
2
Prahlad 18 dic. 2009 a las 08:22

Con la palabra clave let puede evitar esto por completo:

for(let it = 0; it < 2; it++)
{
    setTimeout(function() {
        alert(it);
    }, 1);
}
16
tbondwilkinson 4 dic. 2015 a las 17:48