PDA

View Full Version : javascript e lo scope.. problemini..


aeroxr1
08-07-2013, 20:52
Ciao,
ho un dubbio che non capisco :/

faccio un esempio almeno rendo il tutto di più semplice comprensione :

cosi il tutto funziona correttamente :

var bottoni = document.getElementsByTagName('BUTTON');

for(var i=0; i<menu.length; i++)
{
bottoni[i].onclick = (function(){ // Definisci la funzione in cui ti salvi il valore corrente della i
var currentI = i;
return function(){ // ritorni la funzione (currentI sarà sempre diversa ad ogni iterazione perché cambia lo scope)
recinto.setLevel(currentI);
recinto.inizializzazione();
}
})();
}

mentre se faccio :
for(var i=0; i<3; i++)
{
bottoni[i].onclick = function(){
recinto.setLevel(i);
recinto.inizializzazione();
}

ogni bottone prende setLevel con i=3 .. non capisco.. il passaggio non dovrebbe essere per valore ? come mai qui lo fa come riferimento ???

DanieleC88
09-07-2013, 01:21
Stai creando una funzione in un loop, che in JavaScript è una cosa generalmente sconsigliata esattamente per il "problema" che stai affrontando.

Ciò che accade, in realtà, è che nel loop stai facendo soltanto un'assegnazione, cioè una cosa del tutto simile alla seguente:

for (var i = 0; i < collection.length; ++i) {
object.property = value;
}

Contestualizzando l'esempio al tuo codice, si dà il caso che questo valore sia una funzione (che verrà invocata al click di un pulsante), e questa si accompagna ad una cattura delle variabili dello scope esterno che sono utilizzate al suo interno. In sostanza: stai catturando non il valore dell'indice i al momento dell'iterazione, ma un riferimento ad esso. Al momento del click (e, quindi, dell'invocazione dell'handler), tale indice ha il valore che lo ha fatto uscire dal loop: ecco perché vedi i = 3.

Il tuo primo snippet è corretto. In realtà, però potresti anche evitarti la nuova variabile currentI, visto che stai usando una IIFE (http://en.wikipedia.org/wiki/Immediately-invoked_function_expression), alla quale puoi passare direttamente il valore di i:

var bottoni = document.getElementsByTagName('button');

for (var i=0; i < menu.length; ++i) {
bottoni[i].onclick = (function (i) {
return function() {
recinto.setLevel(i);
recinto.inizializzazione();
};
})(i);
}

In questo modo hai che:

il nome del parametro dell'IIFE sta nascondendo l'omonimo indice del loop esterno, quindi puoi utilizzare senza paura lo stesso nome anche nella funzione più interna;
il valore associato a tale parametro è quello assunto durante la corrispondente iterazione.


HTH

__ZERO_UNO__
09-07-2013, 13:47
Long story short, for non ha scope come le funzioni. Quando la funzione è invocata, i viene cercata e trovata nello scope esterno ed avrà l'ultimo valore che gli è stato assegnato.
Non ragionare in termini di passaggio per valore o riferimento–che non parlando di argomenti di funzione non ha alcun senso–, bensì in termini di scope.

aeroxr1
09-07-2013, 19:16
Long story short, for non ha scope come le funzioni. Quando la funzione è invocata, i viene cercata e trovata nello scope esterno ed avrà l'ultimo valore che gli è stato assegnato.
Non ragionare in termini di passaggio per valore o riferimento–che non parlando di argomenti di funzione non ha alcun senso–, bensì in termini di scope.

giusto :) Ora comunque mi è tutto molto più chiaro :) Grazie ragazzi ! ancora una volta mi avete spiegato qualcosa con un linguaggio semplicissimo :) :cincin: