箭头函数
ES6 引入了箭头函数的概念,这是一种新的定义和编写函数的方法。虽然它看起来像是常规函数的句法糖,但它们之间的关键差异是对 this
的绑定方式。在本文中并不会涉及关于 this
的大量细节
事件侦听器回调
在给浏览器写 JavaScript 时,我们经常会创建事件侦听器。例如:
const toggleElements = document.querySelectorAll('.toggle');
toggleElements.forEach(el => {
el.addEventListener('click', function() {
this.classList.toggle('active');
});
});
在上面的例子中,用了 nodelist.prototype.foreach()
来遍历与指定选择器和eventtarget.addeventlistener()
相匹配的节点,并用常规函数作为 click
事件交换的回调,这个回调用来在单击元素的 active 和 inactive 两个状态之间转换。 当使用常规函数时,回调中的 this
将会绑定到触发事件的元素上。
把箭头函数用作回调
箭头函数没有他自己的绑定到 this
。那么如果把前面的代码段转换为箭头函数,会怎么样?它的 this
指向的是全局的 window
对象。
const toggleElements = document.querySelectorAll('.toggle');
toggleElements.forEach(el => {
el.addEventListener('click', () => {
this.classList.toggle('active'); // “this” 指向 “window”
// Error: Cannot read property 'toggle' of undefined
});
});
由于 window
对象不具有 classlist
属性,所以只要单击匹配的元素,代码都会抛出错误,从而触发事件侦听器并执行回调。 但是一般情况下,代码可能会悄无声息地失败,例如它可能检查某个条件,该条件判断对于 window
总是返回为 false
,而对于给定的元素它应该返回 true
,这会引发许多麻烦并浪费你的时间。
要解决这个问题,可以简单地通过回调函数的第一个参数和 event.target
或 event.currenttarget
,到底用哪个取决于你的需求:
const toggleElements = document.querySelectorAll('.toggle');
toggleElements.forEach(el => {
el.addEventListener('click', (e) => {
e.currentTarget.classList.toggle('active'); // 工作正常
});
});