类语法中传递函数参数时removeClass方法失效问题排查与解决
问题根源:
this 指向“跑偏”了 嘿,这个问题我太熟了——核心就是**this指向丢失**搞的鬼!
当你把 deploy 函数作为参数传给 register 方法,然后在 addEventListener 里调用 fx(e) 时,deploy 内部的 this 已经不再指向你的 Mobile 类实例了,它变成了触发点击事件的那个 <li> DOM 元素!这就导致你调用 this.removeClass 时,this 根本找不到 removeClass 方法,看起来就像是这个方法失效了。
你可以自己验证下:在 deploy 开头加一行 console.log(this),点击菜单后会发现控制台输出的是被点击的 <li>,而不是你的 Mobile 实例。
至于为什么其他方法正常:
Mobile.staticFx('test')是直接通过类名调用静态方法,和this无关,所以没问题;sib.classList.toggle('open')是直接操作获取到的 DOM 元素,也不需要依赖this,所以能正常运行;- 你试的静态方法
Mobile.removeClass(this.listSecond, 'open')失效,是因为此时this是 DOM 元素,this.listSecond是undefined,参数传错了,静态方法本身是没问题的。
三种解决办法,任你选
办法1:注册事件时绑定 this
修改 register 方法,用 bind 把类实例绑定给回调函数,确保 deploy 里的 this 始终指向实例:
register(name, fx) { name.forEach(cur => { // 把类实例的this绑定给fx cur.addEventListener('click', fx.bind(this)); }) }
办法2:构造函数里提前绑定 deploy 的 this
在构造函数里就把 deploy 的 this 固定好,之后不管怎么传递这个函数,this 都不会跑偏:
constructor(elem) { this.elem = document.querySelector(elem); this.list = this.elem.querySelectorAll('li[data="hasChild"]'); this.listSecond = this.elem.querySelectorAll('ul[seq="two"]'); // 提前绑定this到类实例 this.deploy = this.deploy.bind(this); this.register(this.list, this.deploy); }
办法3:用箭头函数包裹回调
箭头函数会继承外层作用域的 this,所以在 register 里用箭头函数包裹回调,再调用 fx 时手动绑定 this:
register(name, fx) { name.forEach(cur => { cur.addEventListener('click', (e) => { // 用call把类实例的this传给fx fx.call(this, e); }); }) }
额外小建议
如果你的类里都是操作实例属性的方法,尽量用实例方法(不要用静态方法),这样代码逻辑更清晰,也不容易出现这类指向问题。
内容的提问来源于stack exchange,提问作者sniffingdoggo
相关产品推荐
相关产品推荐

