2009-11-04 4 views
23

Tenir compte telle boucle:JavaScript et boucle

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

La sortie est:

=> 2 
=> 2 

Je voudrais qu'il soit: 0, 1. Je vois deux façons de le fixer:

Solution # 1.

Celle-ci étant basée sur le fait que nous pouvons transmettre des données à setTimeout.

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

Solution # 2.

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

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

Y at-il d'autres alternatives?

Répondre

42

Pas vraiment quelque chose de plus que les deux façons que vous avez proposées, mais voici une autre

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

Essentiellement, vous devez saisir la valeur de la variable dans une fermeture. Cette méthode utilise une fonction anonyme invoquée immédiatement pour capturer la valeur de la variable externe it dans une variable locale m.

Voici un Working Demo pour jouer avec. ajouter /modifier à l'URL pour voir le code

+4

+1. Cependant, vous pouvez légèrement modifier cela en changeant la signature de la méthode à: 'function (m) {/ * code * /}) (it);' – Alan

+0

+1, mais quelqu'un peut-il m'expliquer pourquoi cela fonctionne ?! –

+1

@digorydoo La fonction déclarée dans la boucle est entourée de parenthèses suivies d'un ensemble de parenthèses qui agissent pour appeler immédiatement la fonction. Puisque les variables sont étendues à la fonction dans laquelle elles sont déclarées (ou portée globale si elles ne sont pas déclarées dans une fonction), la valeur de 'it' dans chaque itération est assignée à la variable' m' qui est étendue à la fonction exécutée immédiatement. –

1

similaires à la solution ci-dessus mais l'auto invocation à l'intérieur de la fonction setTimeout

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

Avec le mot-clé let vous pouvez contourner ce complètement:

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

mais il n'y a pas de mot-clé nommé 'let' en javascript il est en tapuscrit je pense –

1

similaires aux autres solutions, mais dans mon propre avis:

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) 
} 

Cela conserve le même nom de variable pour la capture, et le fait pour toute la boucle, en le séparant de la logique de l'installation du timeout. Si vous voulez ajouter plus de logique à l'intérieur du bloc, vous pouvez le faire trivialement.

La seule chose que je n'aime pas à propos de la solution est la répétition de "ça" à la fin.