2

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

函数重写(旧){
    返回函数(){
        console.log( '添加一些东西到 ' + old.name );
        old.apply(this, arguments);
    }
}
addEventListener=rewrite(addEventListener);

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

函数你好_1(){
    console.log("你好世界 1!");
}
你好_1=重写(你好_1);

需要帮忙!

谢谢!

4

1 回答 1

9

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

因此,您不能真正使用主机提供的函数来执行此操作,因为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 complex可能会很有用。

这是一个完整的例子:

<!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()vs.的问题func(),我想你可能已经明白了,只是我原来的错误答案混淆了问题。但以防万一:apply调用函数,做了两件特殊的事情:

  1. 设置this函数调用中的内容。
  2. 接受作为数组(或任何类似数组的东西)提供给函数的参数。

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

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

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

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

call接受它们作为单独的参数:

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

它们都调用barthis设置foo和传递参数 1、2 和 3。

于 2010-05-23T08:48:23.613 回答