Domanda

    

Questa domanda ha già una risposta qui:

         

Ecco una versione semplificata di una cosa che sto provando a fare funzionare:

for (var i = 0; i < results.length; i++) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', function() { 
        change_selection(i);
    }); 
}

ma mi sto trovando che ogni ascoltatore utilizza il valore della results.length (il valore quando la per termina ciclo). Come posso aggiungere gli ascoltatori in modo tale che ognuno utilizza il valore di i, al momento lo aggiungo, piuttosto che il riferimento a I?

È stato utile?

Soluzione

Nel browser moderni, è possibile utilizzare i let o const parole chiave per creare una variabile di blocco, con ambito:

for (let i = 0; i < results.length; i++) {
  let marker = results[i];
  google.maps.event.addListener(marker, 'click', () => change_selection(i));
}

Nel browser più vecchi, è necessario creare un ambito separato che salva la variabile nel suo stato attuale passando come parametro la funzione:

for (var i = 0; i < results.length; i++) {
  (function (i) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', function() { 
      change_selection(i);
    }); 
  })(i);
}

Con la creazione di una funzione anonima e chiamandolo con la variabile come primo argomento, si sta passando per valore alla funzione e la creazione di una chiusura.

Altri suggerimenti

Oltre alle chiusure, è possibile utilizzare function.bind:

google.maps.event.addListener(marker, 'click', change_selection.bind(null, i));

passa il valore di i come argomento della funzione quando viene chiamato. (null è per this, che non è necessario in questo caso vincolante.)

function.bind è stato introdotto dal framework Prototype ed è stato standardizzato in ECMAScript quinta edizione. Fino a quando i browser tutto il supporto in modo nativo, è possibile aggiungere il proprio supporto function.bind utilizzando le chiusure:

if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        var args= Array.prototype.slice.call(arguments, 1);
        return function() {
            return that.apply(owner,
                args.length===0? arguments : arguments.length===0? args :
                args.concat(Array.prototype.slice.call(arguments, 0))
            );
        };
    };
}

chiusure:

for (var i = 0, l= results.length; i < l; i++) {
    marker = results[i];
    (function(index){
        google.maps.event.addListener(marker, 'click', function() { 
            change_selection(index);
        }); 
    })(i);
}

Modifica 2013: Questi sono ora comunemente noti come IIFE

Si sta liquidazione con una chiusura. Ecco un articolo su chiusure e come lavorare con loro. Scopri Esempio 5 sulla pagina; questo è lo scenario che si sta trattando.

EDIT: Quattro anni dopo, quel collegamento è morto. La radice del problema di cui sopra è che le forme ciclo for chiusure (specificamente marker = results[i]). Come marker è passato in addEventListener, si vede l'effetto collaterale della chiusura: l ' "ambiente" condiviso viene aggiornato con ogni iterazione del ciclo, prima che sia finalmente "salvato" tramite la chiusura dopo l'iterazione finale. MDN spiega molto bene.

for (var i = 0; i < results.length; i++) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', (function(i) {
        return function(){
            change_selection(i);
        }
    })(i)); 
}

Credo che possiamo definire una variabile temporanea per memorizzare il valore di i.

for (var i = 0; i < results.length; i++) {
 var marker = results[i];
 var j = i;
 google.maps.event.addListener(marker, 'click', function() { 
   change_selection(j);
 }); 
}

Non ho provato, però.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top