不幸的是,您不能指望addEventListener 是一个真正的Javascript 函数。 (这适用于其他几个主机提供的函数,例如window.alert)。许多浏览器做正确的事(tm) 并使它们成为真正的 Javascript 函数,但有些浏览器却没有(我在看着你,Microsoft)。如果它不是一个真正的 Javascript 函数,它就没有 apply 和 call 函数作为属性。
因此,您不能真正使用主机提供的函数来执行此操作,因为如果您想将任意数量的参数从代理传递到目标,则需要 apply 功能。相反,您必须使用特定函数来创建知道所涉及的主机函数签名的包装器,如下所示:
// 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);
}
}
当您调用它时,传入一个元素,它会返回一个函数,该函数将通过addEventListener 将事件处理程序连接到该元素。 (请注意,IE8 之前的 IE 没有 addEventListener,而是使用 attachEvent。)
不知道这是否适合您的用例(如果不适合,更详细的用例会很方便)。
你会像这样使用上面的:
// 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);
请注意,我们在调用proxy 时没有将元素引用传递给它;它已经内置在函数中,因为函数是一个闭包。如果您不熟悉它们,我的博文Closures are not complicated 可能会有用。
这是一个完整的例子:
<!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>
关于您下面关于func.apply() 与func() 的问题,我想您可能已经理解了,只是我最初的错误答案混淆了问题。但以防万一:apply 调用函数,做了两件特殊的事情:
- 设置
this 在函数调用中的内容。
- 接受作为数组(或任何类似数组的东西)提供给函数的参数。
您可能知道,Javascript 中的 this 与 C++、Java 或 C# 等其他语言中的 this 完全不同。 Javascript 中的this 与定义函数的位置无关,它完全由函数调用 的方式设置。每次调用函数时,都必须将 this 设置为正确的值。 (更多关于 Javascript here 中的 this 的信息。)有两种方法可以做到这一点:
- 通过对象属性调用函数;将
this 设置为调用中的对象。例如,foo.bar() 将 this 设置为 foo 并调用 bar。
- 通过自己的
apply或call属性调用函数;那些将this 设置为他们的第一个参数。例如,bar.apply(foo) 或 bar.call(foo) 会将 this 设置为 foo 并调用 bar。
apply 和 call 之间的唯一区别是它们如何接受要传递给目标函数的参数:apply 接受它们作为数组(或类似数组的东西):
bar.apply(foo, [1, 2, 3]);
而call 接受它们作为单独的参数:
bar.apply(foo, 1, 2, 3);
它们都调用bar,将this 设置为foo,并传入参数1、2 和3。