软页面跳转场景下JS类window事件监听器移除失败及作用域问题求助
问题根因
- 第一版代码失效原因:resize事件绑定的是匿名箭头函数,没有把函数引用保存到实例属性,执行
removeEventListener时没有传入对应要移除的函数引用,浏览器无法匹配到需要删除的监听器,操作自然不生效。 - 第二版代码失效核心原因:类方法的this上下文绑定问题。如果你为了解决
updateSwiper内部this指向错误的问题,在绑定时写了this.updateSwiper.bind(this),bind方法每次调用都会生成一个全新的函数实例,你没有把这个新生成的函数引用存下来,移除时传入的原始this.updateSwiper和绑定的函数不是同一个引用,浏览器无法匹配到对应监听器,所以移除失败。就算你没有主动bind,直接传this.updateSwiper,虽然移除逻辑本身是匹配的,但事件触发时updateSwiper内部的this会指向window,会出现this.swiper is undefined的运行错误,功能依然不正常。
修复方案
方案1:构造函数内提前绑定方法this
在构造函数里提前把updateSwiper的this绑定到实例,绑定和移除都用同一个实例属性的引用:
export default class Slider extends Core { constructor() { super(); // 提前绑定this,绑定和移除都用这个绑定后的函数 this.updateSwiper = this.updateSwiper.bind(this); } init() { this.swiper = new Swiper('.mySlider', { slidesOffsetBefore: this.sliderOffset(), }); window.addEventListener('resize', this.updateSwiper); } updateSwiper() { this.swiper.params.slidesOffsetBefore = this.sliderOffset(); this.swiper.update(); } removeEventListeners() { window.removeEventListener('resize', this.updateSwiper); } sliderOffset() { // 执行相关逻辑后返回值 return value } }
方案2:类字段箭头函数(更简洁,适合现代JS/TS环境)
直接把updateSwiper定义为类的箭头函数字段,自动绑定this到实例,不需要额外bind:
export default class Slider extends Core { init() { this.swiper = new Swiper('.mySlider', { slidesOffsetBefore: this.sliderOffset(), }); window.addEventListener('resize', this.updateSwiper); } // 箭头函数字段,this自动绑定到当前实例 updateSwiper = () => { this.swiper.params.slidesOffsetBefore = this.sliderOffset(); this.swiper.update(); } removeEventListeners() { window.removeEventListener('resize', this.updateSwiper); } sliderOffset() { // 执行相关逻辑后返回值 return value } }
方案3:使用AbortController(无需维护函数引用,适合多监听器场景)
现代浏览器支持AbortController,可以统一管理多个监听器的销毁,不需要单独记每个函数的引用:
export default class Slider extends Core { init() { this.swiper = new Swiper('.mySlider', { slidesOffsetBefore: this.sliderOffset(), }); // 初始化AbortController this.resizeAbortController = new AbortController(); window.addEventListener('resize', () => { this.swiper.params.slidesOffsetBefore = this.sliderOffset(); this.swiper.update(); }, { signal: this.resizeAbortController.signal }); } removeEventListeners() { // 直接触发abort即可移除所有绑定了对应signal的监听器 this.resizeAbortController?.abort(); } sliderOffset() { // 执行相关逻辑后返回值 return value } }
内容的提问来源于stack exchange,提问作者Albert de Beer
相关产品推荐
相关产品推荐

