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:
- Définit ce
this
sera de l'appel de fonction.
- 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.
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
@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. –
@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