JavaScript类中事件触发类方法失败问题排查
事件回调中无法调用类方法的问题解决
问题场景
已成功创建myClass类并完成实例化,但文本输入框的keyup事件与按钮的click事件触发时,调用类的shuffle方法出现报错:
keyup事件中this.shuffle()提示“不是函数”click事件中self.shuffle()也提示“不是函数”
相关代码如下:
class myClass { constructor(toElement, options) { var self = this; this.toElement = toElement; this.options = options; this.generateElement(); this.shuffle; // works fine } generateElement() { let myElement; myElement = document.createElement('input'); myElement.type = 'text'; myElement.placeholder = 'Search'; myElement.id = 'IDtext'; myElement.addEventListener("keyup", this.eventInputKeyUp); myElement.value = ''; document.getElementById(this.toElement).appendChild(myElement); myElement = document.createElement('input'); myElement.type = 'button'; myElement.id = 'IDbutton'; myElement.value = '▽'; myElement.addEventListener("click", this.eventInputClick); document.getElementById(this.toElement).appendChild(myElement); } eventInputKeyUp() { console.log(this.id) this.shuffle(); // ERROR is not a function } eventInputClick() { console.log(this.id) self.shuffle(); // ERROR in not a function } shuffle() { console.log('shuffle', this.options); } } let x = new myClass('test', 'Hello');
错误原因分析
keyup事件的
this指向错误
事件触发时,回调函数eventInputKeyUp里的this指向的是触发事件的DOM元素(输入框本身),而非myClass的实例。所以this.shuffle不存在,自然报错。click事件的
self作用域无效
构造函数里定义的var self = this;仅在构造函数内部有效,类方法eventInputClick无法访问到这个变量,因此self.shuffle会提示未定义。
解决方案
方法一:构造函数内绑定this
在构造函数中,把类方法的this绑定到类实例,确保事件触发时回调里的this指向正确:
class myClass { constructor(toElement, options) { this.toElement = toElement; this.options = options; // 绑定方法的this到类实例 this.eventInputKeyUp = this.eventInputKeyUp.bind(this); this.eventInputClick = this.eventInputClick.bind(this); this.generateElement(); } generateElement() { let myElement; myElement = document.createElement('input'); myElement.type = 'text'; myElement.placeholder = 'Search'; myElement.id = 'IDtext'; myElement.addEventListener("keyup", this.eventInputKeyUp); myElement.value = ''; document.getElementById(this.toElement).appendChild(myElement); myElement = document.createElement('input'); myElement.type = 'button'; myElement.id = 'IDbutton'; myElement.value = '▽'; myElement.addEventListener("click", this.eventInputClick); document.getElementById(this.toElement).appendChild(myElement); } eventInputKeyUp() { console.log(this.id) this.shuffle(); // 现在this指向类实例,可正常调用 } eventInputClick() { console.log(this.id) this.shuffle(); } shuffle() { console.log('shuffle', this.options); } } let x = new myClass('test', 'Hello');
方法二:箭头函数作为事件回调
箭头函数的this继承自外层作用域(类实例),直接用箭头函数包裹回调即可:
class myClass { constructor(toElement, options) { this.toElement = toElement; this.options = options; this.generateElement(); } generateElement() { let myElement; myElement = document.createElement('input'); myElement.type = 'text'; myElement.placeholder = 'Search'; myElement.id = 'IDtext'; // 箭头函数保留外层this指向 myElement.addEventListener("keyup", () => this.eventInputKeyUp()); myElement.value = ''; document.getElementById(this.toElement).appendChild(myElement); myElement = document.createElement('input'); myElement.type = 'button'; myElement.id = 'IDbutton'; myElement.value = '▽'; myElement.addEventListener("click", () => this.eventInputClick()); document.getElementById(this.toElement).appendChild(myElement); } eventInputKeyUp() { console.log(event.target.id) // 用event.target获取触发事件的DOM元素 this.shuffle(); } eventInputClick() { console.log(event.target.id) this.shuffle(); } shuffle() { console.log('shuffle', this.options); } } let x = new myClass('test', 'Hello');
方法三:类字段定义箭头函数(ES6+)
直接把类方法定义为箭头函数,让this始终指向类实例:
class myClass { constructor(toElement, options) { this.toElement = toElement; this.options = options; this.generateElement(); } generateElement() { let myElement; myElement = document.createElement('input'); myElement.type = 'text'; myElement.placeholder = 'Search'; myElement.id = 'IDtext'; myElement.addEventListener("keyup", this.eventInputKeyUp); myElement.value = ''; document.getElementById(this.toElement).appendChild(myElement); myElement = document.createElement('input'); myElement.type = 'button'; myElement.id = 'IDbutton'; myElement.value = '▽'; myElement.addEventListener("click", this.eventInputClick); document.getElementById(this.toElement).appendChild(myElement); } // 箭头函数定义类方法,this固定指向类实例 eventInputKeyUp = () => { console.log(event.target.id) this.shuffle(); } eventInputClick = () => { console.log(event.target.id) this.shuffle(); } shuffle() { console.log('shuffle', this.options); } } let x = new myClass('test', 'Hello');
内容的提问来源于stack exchange,提问作者Steven Pollentier
相关产品推荐
相关产品推荐

