使用apply()的addEventListener

Pau*_*aul 2 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);

需要帮忙!

谢谢!

T.J*_*der 9

addEventListener不幸的是,你不能指望成为一个真正的Javascript函数.(对于其他几个主机提供的函数也是如此window.alert).许多浏览器都使用Right Thing (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);
    }
}
Run Code Online (Sandbox Code Playgroud)

当你调用它时,传入一个元素,它返回一个函数,它将事件处理程序连接到该元素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);
Run Code Online (Sandbox Code Playgroud)

请注意,我们proxy在调用它时没有将元素引用传递给它; 它已经内置到函数中,因为函数是一个闭包.如果您不熟悉它们,我的博客文章Closures并不复杂可能会有用.

这是一个完整的例子:

<!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>
Run Code Online (Sandbox Code Playgroud)

关于你关于func.apply()vs.的下面的问题func(),我想你可能已经理解了,只是我原来的错误答案让人困惑.但为了以防万一:apply调用函数,做两件特别的事情:

  1. 设置this函数调用中的内容.
  2. 接受将函数作为数组(或类似数组的东西)赋予的参数.

您可能知道,thisJavascript与this其他语言(如C++,Java或C#)完全不同.this在Javascript中与定义函数的位置无关,它完全由函数的调用方式设置.this每次调用函数时都必须设置正确的值.(更多关于thisJavascript的信息.)有两种方法可以做到:

  • 通过对象属性调用函数; 设置this为调用中的对象.例如,foo.bar()设置thisfoo和调用bar.
  • 通过自己applycall属性调用函数; 那些设定this为他们的第一个论点.例如,bar.apply(foo)或者bar.call(foo)将设置thisfoo和调用bar.

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

bar.apply(foo, [1, 2, 3]);
Run Code Online (Sandbox Code Playgroud)

call接受它们作为个别论点:

bar.apply(foo, 1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

那些都调用bar,塞汀thisfoo,并传入参数1,2,和3.