使用apply()的addEventListener

时间:2010-05-23 08:31:28

标签: javascript apply

我正在尝试使用apply()方法调用addEventListener()。代码如下:

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

它不起作用。该代码适用于普通的JavaScript方法,例如

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

需要帮助!

谢谢!

1 个答案:

答案 0 :(得分:9)

不幸的是,你不能指望addEventListener是一个真正的Javascript函数。 (对于其他几个主机提供的函数,例如window.alert)也是如此。许多浏览器都做了正确的事情(tm)并使它们成为真正的Javascript函数,但是有些浏览器没有(我在看你,微软)。如果它不是真正的Javascript函数,它就不会将applycall函数作为属性。

因此,您无法通过主机提供的功能实际执行此操作,因为如果要将代理中的任意数量的参数传递给目标,则需要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调用函数,做两件特别的事情:

  1. 设置函数调用中的this
  2. 接受将函数作为数组(或任何类似数组的东西)赋予的参数。
  3. 您可能知道,Javascript中的this与其他语言(如C ++,Java或C#)中的this完全不同。 Javascript中的this与定义函数的位置无关,它完全由函数调用的方式设置。每次调用函数时,都必须将this设置为正确的值。 (有关herethis的更多信息。)有两种方法可以做到这一点:

    • 通过对象属性调用该函数;将this设置为调用中的对象。例如,foo.bar()this设置为foo并致电bar
    • 通过自己的applycall属性调用该函数;那些将this设置为第一个参数。例如,bar.apply(foo)bar.call(foo)会将this设置为foo并致电bar

    applycall之间的唯一区别是它们如何接受传递给目标函数的参数:apply接受它们作为数组(或类似数组的东西):

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

    call接受它们作为单独的论据:

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

    他们同时致电bar,将this设为foo,并传递参数1,2和3。