2010-04-28 6 views
10

Scopri il seguente frammento di codice HTML/JavaScript:Qual è lo scopo di una variabile Javascript dichiarata in un ciclo 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> 

Questo uscite:

3, 3, 3, 0, 1, 2 

che non è quello che mi aspettavo - mi aspettavo l'uscita 0, 1, 2, 0, 1, 2,

I (erroneamente) presupponeva che la funzione anonima inserita nell'array si comportasse come una chiusura, acquisendo il valore di i assegnato quando viene creata la funzione, ma in realtà sembra che i si comporta come una variabile globale.

Qualcuno può spiegare cosa sta succedendo allo scopo di i in questo esempio di codice e perché la funzione anonima non sta acquisendo il suo valore?

risposta

6

In Javasript, l'unico limite di ambito lessicale "interessante" è il corpo della funzione. Qualunque cosa dichiarata in una funzione (beh, ovunque tranne che in un'altra funzione annidata!) È allo stesso scopo. Ci sono anche alcune cose strane riguardo al modo in cui le dichiarazioni vengono interpretate.

La funzione anonima agisce come una chiusura, ma ciascuna funzione istanziata condividerà la stessa "i". Un trucco che uso è quello di aggiungere un altro strato di funzione:

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

A somepoint si spera tutti i browser sosterrà la nuova dichiarazione "let", che è una, meno strano dall'aspetto modo più breve per fare fondamentalmente la stessa cosa .

8

L'ambito è la funzione in cui la variabile è definita (tranne che non ce n'è una, quindi è globale).

La funzione anonima che si sta passando accede alla variabile definita nello scope (di nuovo globale) della funzione genitore.

È necessaria una chiusura effettiva.

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

     } 
    }(i) 
); 
+0

Risposta corretta - grazie! - ma ho accettato la risposta di Pointy perché "il mio privato" + idaho mi ha fatto ridere ad alta voce ... –