【问题标题】:var a = function() vs function a() for event listener?var a = function() vs function a() 用于事件侦听器?
【发布时间】:2013-05-27 01:37:45
【问题描述】:

我试图了解向事件侦听器添加函数时的区别以及它的含义。

var buttons = document.getElementsByTagName('button');
for (i = 0, len = 3; i < len; i++) {
    var log = function(e) {
        console.log(i);
    }
    buttons[0].addEventListener("click", log);
}

for (i = 0, len = 3; i < len; i++) {
    function log(e) {
        console.log(i);
    }
    buttons[1].addEventListener("click", log);
}

http://jsfiddle.net/paptd/

第一个按钮触发console.log 3 次,而第二个按钮只触发一次。

在正常情况下向事件侦听器添加函数时为什么以及应该使用什么?

【问题讨论】:

  • 对我来说,两个按钮都按预期在您的 jsfiddle 中触发了 3 次。
  • 这里有几点需要注意。 1. 你没有声明i 也没有声明len。 2. 块are bad practice中的函数声明,使用函数表达式代替,这就是问题所在。
  • 如果有兴趣:这里是您关于 javascript 如何因提升而重新排列代码的小提琴:jsfiddle.net/paptd/4
  • @Fallexe,什么浏览器?(这是一个糟糕的浏览器,因为它不遵循 W 行引用的 W3C 规范。)
  • @user1767586 我没有进行更改以改进您的代码。从表面上看,代码的运行方式与以前相同。我只是想向您展示 javascript 如何在内部重新排列变量声明和函数定义。因此,您发布的代码实际上被解释为就好像它是按照我发布的方式编写的一样。

标签: javascript javascript-events


【解决方案1】:

嗯,有几点注意事项:

  • 第一个在每次迭代中创建一个新的log 函数,因此每次添加另一个事件侦听器时都会添加一个新函数。
  • 第二个创建一个全局(阅读关于提升)log 函数,如果在同一个 EventTarget 上使用相同的参数注册了多个相同的 EventListener,则丢弃重复的实例。它们不会导致 EventListener 被调用两次。

规格:

调用 addEventListener(或 removeEventListener)在同一个 EventTarget 上使用相同的参数 type、listener 和 useCapture 的值重复调用无效。 这样做不会导致事件监听器注册更多不止一次,并且不会导致触发顺序发生变化。

source 感谢 Rob W.

所以第二次和第三次迭代什么都不做。

  • 你还有一个闭包问题,最后一次迭代将i 设置为3,这就是控制台中显示的内容。

带闭包的固定版本:

var buttons = document.getElementsByTagName('button');
for (i = 0, len = 3; i < len; i++) {
    var log = (function closure(number) {
        return function () {
            console.log(number);
        }
    })(i);

    buttons[0].addEventListener("click", log);
}

DEMO

【讨论】:

  • 您应该使用对规范的显式引用(在这种情况下,“不需要多次添加相同的函数”不是一个强有力的论点)。相关引用:“在相同的EventTarget 上重复调用addEventListener(或removeEventListener),参数typelisteneruseCapture 的值相同,没有效果。这样做不会导致事件侦听器被注册不止一次,并且不会导致触发顺序发生变化。” - dev.w3.org/2006/webapi/DOM-Level-3-Events/html/…
  • 第二种形式(循环块中的函数声明)实际上是无效的,只有在浏览器添加了非标准行为来处理它时才有效。同样在第二种情况下,log 只有在包含的代码是全局的时才会是全局的,但无论如何都应该避免在块中声明函数。
  • @TimDown,就像:var foo =2; var foo =2; var foo =2;,我不知道规范,但它运行良好......`
  • 是的,它确实在所有浏览器中运行,但如前所述,它需要浏览器的 JS 解析器中的非标准扩展,我认为浏览器实现之间存在差异。此外,由于其他 ECMAScript 环境没有义务支持块内的函数声明,因此代码的可移植性较差。它可以很容易地避免,所以最好这样做。更多背景:kangax.github.io/nfe/#function-statements
  • @TimDown,我不鼓励这样做,我只是解释了它是如何工作的......(:,别担心,我的代码看起来有点不同。
猜你喜欢
  • 1970-01-01
  • 2015-05-27
  • 1970-01-01
  • 2014-11-16
相关资源
最近更新 更多