Skip to content

我可以在JavaScript中使用箭头函数作为事件监听器的回调函数吗?

箭头函数

JavaScript ES6引入了箭头函数的概念,这是一种定义和编写函数的新方式。虽然它们可能看起来只是普通函数的语法糖,但它们有一个关键的区别,就是this上下文的绑定方式。我强烈建议您阅读理解JavaScript中的"this"关键字,因为本文不会详细讨论这个主题。简而言之:

箭头函数没有自己的this绑定,结果是this保留了封闭词法上下文的this的值。

事件监听器回调函数

在编写浏览器端JavaScript时,创建事件监听器是一项常见任务。例如:

const toggleElements = document.querySelectorAll('.toggle');
toggleElements.forEach(el => {
  el.addEventListener('click', function() {
    this.classList.toggle('active');
  });
});

在上面的示例中,我们使用NodeList.prototype.forEach()来迭代匹配的节点,并使用一个普通函数作为'click'事件的回调函数,以在点击的元素之间切换活动和非活动状态。我们使用普通函数,因此回调函数内部的this上下文将绑定到事件目标。

箭头函数作为回调函数

正如我们已经解释过的,箭头函数没有自己的this绑定。那么,如果我们将前面代码片段的回调函数转换为箭头函数,会发生什么呢?它的this上下文将引用全局上下文,也就是Window对象。

const toggleElements = document.querySelectorAll('.toggle');
toggleElements.forEach(el => {
  el.addEventListener('click', () => {
    this.classList.toggle('active'); // `this` 指的是 `Window`
    // 错误:无法读取未定义的属性 'toggle'
  });
});

这段代码会在匹配的元素被点击时触发事件监听器并执行回调函数。然而,它会抛出一个错误,因为 Window 对象没有 classList 属性。通常情况下,代码甚至可能会静默失败。一个例子是对于 Window,条件始终评估为 false,但对于给定的元素可能会评估为 true。这样的问题会导致许多头痛和浪费的时间,直到你能够发现并修复它们。

为了解决这个问题,可以简单地使用回调函数的第一个参数和 Event.targetEvent.currentTarget,具体取决于需求:

const toggleElements = document.querySelectorAll('.toggle');
toggleElements.forEach(el => {
  el.addEventListener('click', (e) => {
    e.currentTarget.classList.toggle('active'); // 正确工作
  });
});