Question

    

Cette question a déjà une réponse ici:

         

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?

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top