基于原型实现的JavaScript图片轮播setInterval上下文丢失问题求助
解决原型模式图片轮播组件中setInterval上下文丢失问题
嘿,我看你用原型模式写图片轮播组件时,碰到了setInterval上下文丢失的问题——这可是JS里相当常见的坑,我来帮你搞定它!
首先得搞明白为啥会丢上下文:setInterval里的普通函数默认会把this指向window(非严格模式下),而不是你的Slide实例。你说试过bind和函数包装没效果,大概率是用法没到位,下面给你几种靠谱的解决办法:
方案一:用变量缓存实例上下文
这是最经典也最兼容的写法,在构造函数里把当前实例存成一个变量(比如self或者that),之后在setInterval的回调里用这个变量代替this就行:
function Slide() { this.currentStep = 0; this.time = 2000; this.images = [ 'images/image1.jpg', 'images/image2.jpg', 'images/image3.jpg', 'images/image4.jpg' ]; // 缓存当前Slide实例 const self = this; // 启动轮播方法 this.start = function() { this.intervalId = setInterval(function() { // 用self代替this,就能访问到实例的属性了 self.currentStep = (self.currentStep + 1) % self.images.length; console.log('当前显示图片:', self.images[self.currentStep]); // 这里写更新DOM的逻辑,比如替换img标签的src属性 }, this.time); }; // 停止轮播方法 this.stop = function() { clearInterval(this.intervalId); }; }
方案二:用ES6箭头函数绑定上下文
箭头函数的特性就是自动继承外层作用域的this,所以直接在setInterval里用箭头函数当回调,this就会指向你的Slide实例,写法更简洁:
function Slide() { this.currentStep = 0; this.time = 2000; this.images = [ 'images/image1.jpg', 'images/image2.jpg', 'images/image3.jpg', 'images/image4.jpg' ]; this.start = function() { this.intervalId = setInterval(() => { // 箭头函数里的this直接指向Slide实例 this.currentStep = (this.currentStep + 1) % this.images.length; console.log('当前显示图片:', this.images[this.currentStep]); // 更新DOM逻辑 }, this.time); }; this.stop = function() { clearInterval(this.intervalId); }; }
方案三:用bind绑定回调函数上下文
如果你的轮播方法是挂在原型上的,那要注意给setInterval的回调函数绑定实例的this,或者在构造函数里提前绑定原型方法的上下文:
function Slide() { this.currentStep = 0; this.time = 2000; this.images = [ 'images/image1.jpg', 'images/image2.jpg', 'images/image3.jpg', 'images/image4.jpg' ]; // 提前给原型上的start方法绑定当前实例的上下文 this.start = this.start.bind(this); } // 原型上的启动方法 Slide.prototype.start = function() { this.intervalId = setInterval(function() { this.currentStep = (this.currentStep + 1) % this.images.length; console.log('当前显示图片:', this.images[this.currentStep]); }.bind(this), this.time); // 也可以直接给回调函数bind(this) }; Slide.prototype.stop = function() { clearInterval(this.intervalId); };
小提示
你之前试bind没效果,可能是没找对绑定的位置:比如只绑定了start方法,但没给setInterval里的回调函数绑定this,或者绑定的不是实例的上下文。另外一定要把setInterval返回的定时器ID存在实例属性里(比如this.intervalId),这样stop方法才能正确清除定时器哦。
内容的提问来源于stack exchange,提问作者Norayr Ghukasyan
相关产品推荐
相关产品推荐

