Voici une version simplifiée de quelque chose que j'essaie d'exécuter:
for (var i = 0; i < results.length; i++) {
marker = results[i];
google.maps.event.addListener(marker, 'click', function() {
change_selection(i);
});
}
mais je constate que chaque écouteur utilise la valeur de results.length (la valeur à la fin de la boucle for). Comment puis-je ajouter des écouteurs de telle sorte que chacun utilise la valeur de i au moment où je l'ajoute, plutôt que la référence à i?
Dans les navigateurs modernes, vous pouvez utiliser les mots clés let
ou const
pour créer une variable de portée bloc:
for (let i = 0; i < results.length; i++) {
let marker = results[i];
google.maps.event.addListener(marker, 'click', () => change_selection(i));
}
Dans les navigateurs plus anciens, vous devez créer une portée distincte qui enregistre la variable dans son état actuel en la passant comme paramètre de fonction:
for (var i = 0; i < results.length; i++) {
(function (i) {
marker = results[i];
google.maps.event.addListener(marker, 'click', function() {
change_selection(i);
});
})(i);
}
En créant une fonction anonyme et en l'appelant avec la variable comme premier argument, vous passez par valeur à la fonction et créez une fermeture.
Outre les fermetures, vous pouvez utiliser function.bind
:
google.maps.event.addListener(marker, 'click', change_selection.bind(null, i));
transmet la valeur de i
in comme argument à la fonction lorsqu'elle est appelée. (null
est pour la liaison this
, dont vous n'avez pas besoin dans ce cas.)
function.bind
a été introduit par le framework Prototype et a été normalisé dans ECMAScript Fifth Edition. Jusqu'à ce que les navigateurs le prennent tous en charge de manière native, vous pouvez ajouter votre propre function.bind
prise en charge à l'aide de fermetures:
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))
);
};
};
}
fermetures:
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);
}
EDIT, 2013: Ceux-ci sont maintenant communément appelés IIFE
Vous vous retrouvez avec une fermeture. Voici un article sur les fermetures et comment travailler avec eux. Consultez l'exemple 5 sur la page; c'est le scénario auquel vous avez affaire.
EDIT: Quatre ans plus tard, ce lien est mort. La racine du problème ci-dessus est que la boucle for
forme des fermetures (en particulier sur marker = results[i]
). Lorsque marker
est passé dans addEventListener
, vous voyez l'effet secondaire de la fermeture: "l'environnement" partagé est mis à jour à chaque itération de la boucle, avant d'être finalement "enregistré" via la fermeture après l'itération finale. MDN l'explique très bien.