2010-05-23 5 views
2

J'essaie d'invoquer addEventListener() en utilisant la méthode apply(). Le code est comme:addEventListener using apply()

 
function rewrite(old){ 
    return function(){ 
     console.log('add something to ' + old.name); 
     old.apply(this, arguments); 
    } 
} 
addEventListener=rewrite(addEventListener); 

Cela ne fonctionne pas. Le code fonctionne pour la méthode JavaScript normale, par exemple,

 
function hello_1(){ 
    console.log("hello world 1!"); 
} 
hello_1=rewrite(hello_1); 

Besoin d'aide!

Merci!

Répondre

8

Vous ne pouvez pas compter sur addEventListener étant une véritable fonction Javascript, malheureusement. (Cela est vrai de plusieurs autres fonctions fournies par l'hôte, comme window.alert). De nombreux navigateurs font la bonne chose (tm) et en font de véritables fonctions Javascript, mais certains navigateurs ne le font pas (je vous regarde, Microsoft). Et si ce n'est pas une vraie fonction Javascript, il n'aura pas les fonctions apply et call dessus comme propriétés.

Par conséquent, vous ne pouvez pas vraiment le faire génériquement avec des fonctions fournies par l'hôte, car vous avez besoin de la fonctionnalité apply si vous voulez passer un nombre arbitraire d'arguments de votre proxy à votre cible. Au lieu de cela, vous devez utiliser des fonctions spécifiques pour créer les emballages qui connaissent la signature de la fonction hôte impliqué, comme ceci:

// Returns a function that will hook up an event handler to the given 
// element. 
function proxyAEL(element) { 
    return function(eventName, handler, phase) { 
     // This works because this anonymous function is a closure, 
     // "closing over" the `element` argument 
     element.addEventListener(eventName, handler, phase); 
    } 
} 

Lorsque vous appelez ça, en passant dans un élément, il retourne une fonction qui brancher gestionnaires d'événements à cet élément via addEventListener. (Notez que IE avant IE8 n'a pas addEventListener, cependant, il utilise attachEvent à la place.)

Je ne sais pas si cela convient à votre cas d'utilisation ou non (sinon, plus de détails sur le cas d'utilisation serait pratique).

Vous utiliseriez ci-dessus comme ceci:

// Get a proxy for the addEventListener function on btnGo 
var proxy = proxyAEL(document.getElementById('btnGo')); 

// Use it to hook the click event 
proxy('click', go, false); 

Notez que nous ne passons la référence de l'élément en proxy lorsque nous l'avons appelé; il est déjà intégré dans la fonction, car la fonction est une fermeture. Si vous n'êtes pas familier avec eux, mon article de blog Closures are not complicated peut être utile.

Voici un exemple complet:

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"> 
<title>Test Page</title> 
<style type='text/css'> 
body { 
    font-family: sans-serif; 
} 
#log p { 
    margin:  0; 
    padding: 0; 
} 
</style> 
<script type='text/javascript'> 

    window.onload = pageInit; 
    function pageInit() { 
     var proxy; 

     // Get a proxy for the addEventListener function on btnGo 
     proxy = proxyAEL(document.getElementById('btnGo')); 

     // Use it to hook the click event 
     proxy('click', go, false); 
    } 

    // Returns a function that will hook up an event handler to the given 
    // element. 
    function proxyAEL(element) { 
     return function(eventName, handler, phase) { 
      // This works because this anonymous function is a closure, 
      // "closing over" the `element` argument 
      element.addEventListener(eventName, handler, phase); 
     } 
    } 

    function go() { 
     log('btnGo was clicked!'); 
    } 

    function log(msg) { 
     var p = document.createElement('p'); 
     p.innerHTML = msg; 
     document.getElementById('log').appendChild(p); 
    } 

</script> 
</head> 
<body><div> 
<input type='button' id='btnGo' value='Go'> 
<hr> 
<div id='log'></div> 
</div></body> 
</html> 

En ce qui concerne votre question ci-dessous à propos func.apply() vs func(), je pense que vous avez probablement déjà compris, il est juste que mon original mauvaise réponse fait qu'embrouiller les choses. Mais juste au cas où: la fonction apply appels, faire deux choses spéciales:

  1. Définit ce this sera de l'appel de fonction.
  2. Accepte les arguments à donner à la fonction sous la forme d'un tableau (ou d'un objet de type tableau).

Comme vous le savez sans doute, this en Javascript est tout à fait différent de this dans d'autres langages comme le C++, Java ou C#. this dans Javascript n'a rien à voir où une fonction est définie, elle est entièrement définie par la façon dont la fonction est appelée.Vous devez définir this à la valeur correcte chaque fois que vous appelez une fonction. (En savoir plus sur this en Javascript here.) Il y a deux façons de le faire:

  • en appelant la fonction via une propriété d'objet; cela définit this à l'objet dans l'appel. par exemple, foo.bar() définit this à foo et appelle bar. En appelant la fonction via ses propres propriétés apply ou call;ceux réglés this à leur premier argument. Par exemple, bar.apply(foo) ou bar.call(foo) définir this à foo et appeler bar.

La seule différence entre apply et call comment ils acceptent les arguments pour passer à la fonction cible: apply les accepte comme un tableau (ou une chose semblable à un tableau):

bar.apply(foo, [1, 2, 3]); 

alors que call les accepte comme arguments individuels:

bar.apply(foo, 1, 2, 3); 

les deux bar appel, seting this t o foo, et en passant les arguments 1, 2 et 3.

+0

Je ne pourrais pas connaître la signature de addEvetnListener car cela pourrait se produire en cours d'exécution. Y a-t-il une solution de contournement? – Paul

+0

@Paul: 'addEventListener' a une signature spécifique définie. Pour de vraies fonctions * Javascript *, dans le cas général, vous pouvez faire ce que vous avez fait. Ce sont simplement ces fonctions ennuyeuses fournies par l'hôte qui peuvent ne pas être "réelles" que vous devez contourner, et celles-ci auront des signatures définies. –

+0

@Crowder, Désolé, j'ai soit mal compris ou mal exprimé ... Ce que j'ai essayé de dire, c'est que, vu votre exemple de code, comment puis-je connaître l'élément? (J'utilise Firefox.) Aussi, quelle est la différence entre func.apply() et func() (c'est-à-dire, quelle est la différence entre votre code et mon code)? Merci! – Paul