问题分析
最近一个js问题困扰了2小时:现在我们需要定义一个类,类里面初始化对象时会绑定事件,然后销毁方法会解绑事件,精简代码如下:(这里使用es6定义类的方式,使用原始的function思路也是一样的)
class Test {
constructor() {
this.width = 0;
}
//初始化对象时使window绑定事件resize,设置对象宽度
init(){
window.addEventListener("resize",this.resize);
}
//销毁方法,解绑事件
destroy(){
window.removeEventListener("resize",this.resize);
}
//监测window宽度变化,复值给对象的width属性
resize(){
console.log(this);
this.width = document.body.clientWidth;
}
}
//创建并初始化对象
let test = new Test;
test.init();
已知问题:根据事件绑定中,谁调用,this就指向谁,得知resize中的this其实是指向window,不能实现我们需要的效果,这个比较容易理解。
已知限制:
- 1、在不改变this指向情况下,resize函数里面的this永远指向调用它的window
- 2、绑定事件和解绑事件中第二个参数必须是同一个函数引用
- 3、因为绑定事件和解绑事件中第二个参数必须是同一个函数引用,所以不能直接传参数
因为上面的3个限制,所以想了很多中方法都失败告终,最终还是必须使用bind方法改变this指向,同时存储bind方法返回的匿名函数,然后再传给事件绑定方法。
ps:js的bind方法能改变this指向,并返回一个新的匿名函数,但不会执行函数。例如:this.resize.bind(this)
解决代码
详细说明请看注释
class Test {
constructor() {
this.width = 0;
this.newResize = null; //此属性用于保存bind返回的匿名函数
}
//初始化对象时使window绑定事件resize,设置对象宽度
init(){
//使用bind改变this指向,并保存返回的匿名函数
this.newResize = this.resize.bind(this);
window.addEventListener("resize",this.newResize )
}
//销毁,解绑事件
destroy(){
window.removeEventListener("resize",this.newResize );
}
//监测window宽度变化,复值给对象的width属性
resize(){
console.log(this);
this.width = document.body.clientWidth;
}
}
let test = new Test;
test.init();
如果解决了你的问题,点个赞 ^_^