【问题标题】:addEventListener using apply()addEventListener 使用 apply()
【发布时间】:2011-02-22 21:09:57
【问题描述】:

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

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

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

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

需要帮助!

谢谢!

【问题讨论】:

    标签: javascript apply


    【解决方案1】:

    不幸的是,您不能指望addEventListener 是一个真正的Javascript 函数。 (这适用于其他几个主机提供的函数,例如window.alert)。许多浏览器做正确的事(tm) 并使它们成为真正的 Javascript 函数,但有些浏览器却没有(我在看着你,Microsoft)。如果它不是一个真正的 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. 接受作为数组(或任何类似数组的东西)提供给函数的参数。

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

    • 通过对象属性调用函数;将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。

    【讨论】:

    • 我可能不知道 addEvetnListener 的签名,因为它可能发生在运行时。有什么解决办法吗?
    • @Paul: addEventListener 有一个特定的、已定义的签名。对于真正的 Javascript 函数,在一般情况下,你可以做你所做的。只是这些讨厌的主机提供的功能可能不是“真实的”,您必须解决这些功能,并且这些功能将具有定义的签名。
    • @Crowder,对不起,我误解或误会...我想说的是,鉴于您的示例代码,我怎么知道元素? (我使用的是 Firefox。)另外,func.apply() 和 func() 之间有什么区别(即,你的代码和我的代码有什么区别)?谢谢!
    • @Paul:我不知道我在想什么,上面的行不通。我在考虑addEventListener 接受元素作为第一个参数,但当然它不会那样做,它被称为元素的方法。休息日,恐怕。我去更新(并回答关于apply的问题)。
    • @T.J.,非常感谢您提供的详细信息。 addEventListener 和其他一些主机提供的函数不是“真正的”函数,是因为它们是原生 JavaScript 函数吗?也许这个问题可以这样问:是所有原生 JavaScript 函数都没有 apply() 还是只是某些原生函数没有?
    猜你喜欢
    • 2021-04-03
    • 2014-01-29
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 2019-07-22
    • 1970-01-01
    • 2014-02-12
    • 2021-12-14
    相关资源
    最近更新 更多