Comment puis-je passer la valeur (pas la référence) d'une variable JS à une fonction? [dupliquer]
-
24-09-2019 - |
Question
Cette question a déjà une réponse ici:
- fermeture JavaScript boucles à l'intérieur - simples exemple pratique 44 réponses
Voici une version simplifiée de quelque chose que je suis en train de courir:
for (var i = 0; i < results.length; i++) {
marker = results[i];
google.maps.event.addListener(marker, 'click', function() {
change_selection(i);
});
}
mais je trouve que chaque auditeur utilise la valeur de results.length (la valeur lorsque la boucle se termine). Comment puis-je ajouter des écouteurs tels que chacun utilise la valeur de i au moment où je l'ajoute, plutôt que la référence à i?
La solution
Dans les navigateurs modernes, vous pouvez utiliser les mots-clés ou let
const
pour créer une variable scope bloc:
for (let i = 0; i < results.length; i++) {
let marker = results[i];
google.maps.event.addListener(marker, 'click', () => change_selection(i));
}
Dans les anciens navigateurs, vous devez créer un champ distinct qui permet d'économiser la variable dans son état actuel en 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 de l'appeler à la variable comme premier argument, vous passez par valeur à la fonction et la création d'une fermeture.
Autres conseils
En plus des fermetures, vous pouvez utiliser function.bind
:
google.maps.event.addListener(marker, 'click', change_selection.bind(null, i));
transmet la valeur de i
comme argument de la fonction lorsqu'il est appelé. (null
est pour la liaison this
, que vous n'avez pas besoin dans ce cas.)
function.bind
a été introduit par le cadre du prototype et a été normalisé dans ECMAScript Cinquième édition. Tant que les navigateurs prennent en charge tous nativement, vous pouvez ajouter votre propre support function.bind
en utilisant des 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 Ia vie
Vous enroulement 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 que vous avez affaire.
EDIT: Quatre ans plus tard, ce lien est mort. La racine du problème ci-dessus est que la boucle de fermeture for
forme (en particulier sur marker = results[i]
). Comme 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 qu'il ne soit finalement « sauvé » par la fermeture après la dernière itération. explique très MDN bien.
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));
}
Je pense que nous pouvons définir une variable temporaire pour stocker la valeur de 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);
});
}
Je ne l'ai pas testé cependant.