javascript - 如何使用闭包在循环内设置事件监听器

标签 javascript closures dom-events

thisKey.addEventListener(
  'mousedown',
  (function(_temp) {
    return function() {
      fnPlayKeyboard({
        keyCode: _temp
      });
    }
  })(reverseLookup[n + ',' + i])
);

看到这行代码,我对 addEventListener 的第二个参数中的函数如何工作感到困惑。我知道总体目标是在单击键盘上的按键时播放正确的声音。

在其余代码中,fnPlayKeyboard 接受事件 e 作为参数,并根据 e.keyCode 播放音符。 verseLookup 应该查找给定音符的 keyCode,此处用 n+','+i 表示。

我猜测代码以某种方式将 mousedown 事件转换为 keydown 事件,但不确定它是如何做到这一点的。让我特别困惑的是语法,因为似乎有一个 double ()() 作为 addEventListener 的第二个参数。

最佳答案

这是一个立即调用并返回另一个函数的函数。然后返回的函数被指定为 mousedown 监听器。

由于尝试创建函数范围变量 _temp 来摆脱闭包内循环问题,因此可能会非常复杂。如果ES2015允许,那就清楚多了。该代码相当于:

// ES2015
const keyCode = reverseLookup[n + ',' + i];
thisKey.addEventListener('mousedown', () => {
  fnPlayKeyboard({ keyCode });
});

它采用 ni 变量,无论它们是什么,并在 reverseLookup(可能是一个对象)上查找它们,以获取keyCode。然后,当 thisKey 收到 mousedown 事件时,它会使用具有该 keyCode 的对象调用 fnPlayKeyboard

代码不一定等同于

// Pre-ES2015
var keyCode = reverseLookup[n + ',' + i];
thisKey.addEventListener('mousedown', function() {
  fnPlayKeyboard({ keyCode: keyCode });
});

因为,如果代码位于循环内,则 keyCode 只会有一个绑定(bind)(这将是在循环的最终迭代中分配给它的最终值):

// Pre-ES2015
for (var i = 0; i < 10; i++) {
  var keyCode = reverseLookup[n + ',' + i];
  thisKey.addEventListener('mousedown', function() {
    fnPlayKeyboard({ keyCode: keyCode });
  });
}

上面的代码不会按预期工作,但仅在 ES2015+ 环境中允许通过使用 const 声明变量来修复它。在较旧的环境中,立即在 addEventListener 中调用匿名 (function(_temp) { return function() { 是确保监听器拥有正确 >keyCode 调用时,通过仅为此监听器创建函数范围变量(_temp 参数)。

关于javascript - 如何使用闭包在循环内设置事件监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60142224/

相关文章:

design-patterns - 这种带有闭包的模式有名字吗?

ios - 无法调用来自 SDWebImage 的调用

javascript - JavaScript 中的鼠标和键盘事件名称

javascript - 如何在Ember中获取点击事件的目标元素?

Javascript:延迟加载图像的自定义脚本出错

javascript - 防止绝对定位的 div 在不禁用滚动条的情况下吞噬点击事件

javascript - 如何在 IE 中禁用 Alt-Enter?

javascript - "undefined"和未定义有什么区别?

scala - 匿名函数中的Scala返回语句

javascript - 在 JavaScript 中获取两位小数而不四舍五入到下一个更大的数字