Come faccio a passare il valore (non il riferimento) di una variabile JS a una funzione? [duplicare]
-
24-09-2019 - |
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?
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ò.