2010-12-10 4 views
1

J'utilise un tel code pour transmettre des arguments aux fonctions du gestionnaire d'événements. Mais, dans ce cas particulier, la boucle cause des problèmes. Seul le dernier linkTags [i] est accessible dans tous les appels actifsVisual. Cela a à voir avec le fait que la fonction anonyme qui passe l'argument est une seule et même chose pour toute la boucle.Puis-je transmettre une nouvelle fonction anonyme à addEventListener?

for (var i = 0; i < linkTags.length; i++) { 
    addCrossEvent(linkTags[i], "click", launchLink); 
    addCrossEvent(linkTags[i], "mousedown", 
     function(evt) { 
     activeVisual(evt, linkTags[i]); 
     }); 
    } 

Maintenant, je me souviens avoir essayé d'ajouter de nouvelles avant la déclaration de fonction anonyme comme ceci:

for (var i = 0; i < linkTags.length; i++) { 
    addCrossEvent(linkTags[i], "click", launchLink); 
    addCrossEvent(linkTags[i], "mousedown", 
     new function(evt) { 
     activeVisual(evt, linkTags[i]); 
     }); 
    } 

Il ne fonctionne pas. L'ActiveVisual n'est jamais appelé. Quelqu'un peut-il m'expliquer pourquoi et comment puis-je le faire fonctionner, s'il vous plaît?

MISE À JOUR SOLUTION FINALE

Merci à toutes les réponses ci-dessous mon code TRAVAIL ressemble maintenant à ceci:

// Function that provides pass of event handling parameters with separate copy in each loop 
    function callbackHandler(index) { 
    return function(evt) { 
     activeVisual(evt, linkTags[index]); 
    } 
    } 
    ... 
    for (var i = 0; i < linkTags.length; i++) { 
    ... 
    addCrossEvent(linkTags[i], "mousedown", callbackHandler(i)); 
    } 

Répondre

5

Vous devez faire ceci:

addCrossEvent(linkTags[i], "mousedown", 
     (function(i) { 
      return function(evt) { 
       activeVisual(evt, linkTags[i]); 
      } 
    )(i); 
); 

Le problème est avec le iterator variable i qui change à chaque itération, et une référence est passée, la valeur de i n'est pas copiée. Le passer de cette façon en tant que paramètre à une fonction wrapper provoquera une copie et recevra la valeur réelle à cette itération particulière.

+0

Si l'itérateur i variable est le problème comment se fait-il ne provoque pas de problèmes dans cette ligne addCrossEvent (linkTags [i], "cliquez sur", launchLink); ? Est-il seulement passé par la référence aux fonctions anonymes? –

+1

parce que lorsque vous ajoutez addCrossEvent (linkTags [i], "click", launchLink); vous avez la valeur i dans le tableau linkTags pour chaque boucle, mais quand la fonction est appelée sur l'événement, j'ai la dernière valeur, et vous avez seulement la même position dans le tableau – madeinstefano

+1

@ avok00: Dans 'addCrossEvent (linkTags [i ], "click", launchLink) 'vous passez la valeur de' linkTags [i] 'directement à la fonction.Mais 'activeVisual (evt, linkTags [i]);' dans le * callback * est évalué lorsque le callback est appelé, * not * dans la boucle. Mais quand le callback est appelé, la boucle est déjà terminée et 'i' a sa valeur finale. –

2

Pour être complet, voici une explication pourquoi votre façon d'utiliser new ne fonctionne pas:

Lorsque vous appelez une fonction avec new, la fonction génère un objet vide (que vous pouvez consulter avec this dans la fonction et qui hérite du prototype de fonctions) et le renvoie.
Donc, vous ne passez pas une fonction en tant que gestionnaire de rappel, mais l'objet renvoyé par la fonction.

Ce n'est pas un problème tant que l'objet implémente le EventListner interface afin d'être utilisable en tant que gestionnaire d'événements. Si vous faites cela, vous pouvez utiliser votre code avec quelques modifications:

for (var i = 0; i < linkTags.length; i++) { 
    addCrossEvent(linkTags[i], "click", launchLink); 
    addCrossEvent(linkTags[i], "mousedown", 
     new (function(index) { 
     this.handleEvent = function(evt) { 
      activeVisual(evt, linkTags[index]); 
     } 
     })(i)); 
    } 

Ceci est en fait similaire à @ la réponse de Luca, parce que la valeur de i est capturée lors de la création d'objets. Le code supérieur est en fait identique à:

function CallbackHandler(index) { 
    this.handleEvent = function(evt) { 
     activeVisual(evt, linkTags[index]); 
    } 
} 

for (var i = 0; i < linkTags.length; i++) { 
    addCrossEvent(linkTags[i], "click", launchLink); 
    addCrossEvent(linkTags[i], "mousedown", new CallbackHandler(i)); 
} 

Cela dit, je trouve l'utilisation d'une fonction immédiate qui retourne une fonction plus facile à lire et je pense que l'aide d'une fonction de gestionnaire d'événements au lieu d'un objet est trop plus fréquent.

Working DEMO

+0

+1 Pour une très bonne solution et explication. Désolé de dire cela ne fonctionne dans IE8, il ne peut pas comprendre pas this.handleEvent –

+0

:(@ avok00: Peut-être ... IE est toujours un peu spécial;) Mais la raison pourrait aussi être que le 'event' objet doit être récupéré différemment dans IE. Pour plus d'informations sur la gestion des événements et des problèmes de navigateur, consultez http://www.quirksmode.org/js/introevents.html –

Questions connexes