2010-04-28 6 views
10

Consultez l'extrait suivant du code HTML/Javascript:Quelle est la portée d'une variable Javascript déclarée dans une boucle for()?

<html> 
<head> 
<script type="text/javascript"> 
var alerts = []; 
for(var i = 0; i < 3; i++) { 
    alerts.push(function() { document.write(i + ', '); }); 
} 

for (var j = 0; j < 3; j++) { 
    (alerts[j])(); 
} 

for (var i = 0; i < 3; i++) { 
    (alerts[i])(); 
} 
</script> 
</head><body></body></html> 

Ce sorties:

3, 3, 3, 0, 1, 2 

qui est pas ce que je me attendais - je me attendais à la sortie 0, 1, 2, 0, 1, 2,

I (incorrectement) supposé que la fonction anonyme poussée dans le tableau se comporterait comme une fermeture, en capturant la valeur de i qui est affectée lorsque la fonction est créée - mais il semble que i se comporte comme une variable globale.

Quelqu'un peut-il expliquer ce qui se passe à la portée de i dans cet exemple de code, et pourquoi la fonction anonyme ne capture pas sa valeur?

Répondre

6

Dans Javasript, la seule limite de portée lexicale «intéressante» est le corps de la fonction. Tout ce qui est déclaré n'importe où dans une fonction (eh bien, n'importe où autre qu'une autre fonction imbriquée!) A la même portée. Il y a aussi des choses étranges sur la façon dont les déclarations sont interprétées.

Votre fonction anonyme agit comme une fermeture, mais chaque fonction instanciée partagera le même "i". Une astuce que j'utilise est d'ajouter une autre couche de fonction:

for (var i = 0; i < whatever; i++) { 
    (function(idaho) { 
    whatever(function() { alert("my own private " + idaho); }); 
    })(i); 
} 

À somepoint, espérons tous les navigateurs soutiendront la nouvelle « let » déclaration, qui est plus courte, moins bizarrement prospectifs faire essentiellement la même chose .

8

La portée est la fonction dans laquelle la variable est définie (sauf qu'il n'y en a pas, elle est donc globale).

La fonction anonyme que vous transmettez accède à la variable définie dans la portée de la fonction parent (de nouveau globale).

Vous avez besoin d'une fermeture réelle.

alerts.push(
    function (foo) { 
     return function() { 
      document.write(foo + ', '); 

     } 
    }(i) 
); 
+0

Bonne réponse - merci! - mais j'ai accepté la réponse de Pointy parce que "mon propre privé" + idaho m'a fait rire à haute voix ... –

Questions connexes