如何解决JavaScript类中addEventListener事件监听的this指向错误问题
问题原因
- 上下文指向错误:
addEventListener绑定的回调函数默认this指向触发/绑定事件的对象(这里是document),而非ProfileCollaboration类的实例,所以调用this.enableEditingMode时无法在document上找到对应方法。 - 方法名拼写错误:类中定义的方法名为
enableEditingMod(末尾缺少字母e),调用时写的是enableEditingMode,名称不匹配也会触发不存在的报错。
正确解决方案
方案1:在构造函数中绑定实例this
在绑定事件时用bind方法把回调的this固定为类实例,同时修正拼写错误即可:
class ProfileCollaboration { constructor() { // 用bind将回调的this绑定为当前类实例 document.addEventListener('profileEvent', this.profileEvent.bind(this)) } profileEvent(event) { let profileEvent = event.detail if (profileEvent.name !== 'profileEditing') { return } if (profileEvent.editing === true) { this.enableEditingMode() } else { this.disableEditingMode() } } // 修正拼写错误,补全末尾的e enableEditingMode() { console.log('enabled'); } disableEditingMode() { console.log('disabled'); } }
方案2:用类字段箭头函数定义回调
用箭头函数定义事件处理方法,箭头函数的this会继承自类实例的上下文,不需要额外绑定:
class ProfileCollaboration { constructor() { document.addEventListener('profileEvent', this.profileEvent) } // 箭头函数类字段,this永远指向类实例 profileEvent = (event) => { let profileEvent = event.detail if (profileEvent.name !== 'profileEditing') { return } if (profileEvent.editing === true) { this.enableEditingMode() } else { this.disableEditingMode() } } enableEditingMode() { console.log('enabled'); } disableEditingMode() { console.log('disabled'); } }
方案3:事件绑定处直接用箭头函数包裹回调
class ProfileCollaboration { constructor() { // 箭头函数的this继承自constructor的上下文(即类实例) document.addEventListener('profileEvent', (e) => this.profileEvent(e)) } profileEvent(event) { let profileEvent = event.detail if (profileEvent.name !== 'profileEditing') { return } if (profileEvent.editing === true) { this.enableEditingMode() } else { this.disableEditingMode() } } enableEditingMode() { console.log('enabled'); } disableEditingMode() { console.log('disabled'); } }
补充说明:如果后续需要移除事件监听,不要使用方案3的匿名箭头函数,因为无法拿到相同的函数引用进行移除,优先使用方案1或方案2,移除时直接传入绑定后的方法引用即可。
内容的提问来源于stack exchange,提问作者Grifting
相关产品推荐
相关产品推荐

