修改setInterval作用域
Hello,今天和大家分享如何修改setInterval作用域。
0.引子
最近在做一个项目的时候需要开发一个图片轮播显示的组件,在实现过程中遇到了关于setInterval作用域的问题。
1 SlidePicture.prototype={
2 constructor:SlidePicture,
3 init:function(){ //初始化函数
4 this.autoPlay();
5 },
6 slidePic:function(){ //滑动图片具体实现
7 //省略实现代码
8 console.log('duration-->'+this.duration);
9 console.log('delay-->'+this.delay);
10 },
11 autoPlay:function(){ //自动轮播图片
12 setInterval(this.slidePic,this.delay);
13 }
14 }
15 //构造函数
16 function SlidePicture(delay,duration){
17 this.delay=delay;
18 this.duration=duration;
19 this.init();
20 }
21
22 var sp=new SlidePicture(5000,800);
在上面的代码中,我们自定义并扩展一个SlidePicture原型。主要总用就是,我们在创建原型对象时会调用window的setInterval方法,
来定时调用图片切换方法,从而实现自动图片的自动轮播效果。
slidePic方法中具体的实现方法我先省略了(下次可以继续和大家分享这个完整的组件),只是在这里打印了对象中的两个属性值,
结果却出现以下信息:
都是undefined,为什么呢?
很明显问题不是出在SlidePicture对象上,因为我们已经给这个对象初始化过属性值了。
打开firebug脚本调试,在第8行打上断点:
终于发现了问题所在:slidePic方法中的this居然是指向window而不是当前的SlidePicture对象。
1.问题
我们重新审查代码,结果把关注点提到第12行来:
setInterval(this.slidePic,this.delay);
问题来了,setInterval以及setTimeout这些方法都是全局作用域window的函数,
所以上面的代码等价于:
1 setInterval(function(){ 2 console.log('duration-->'+this.duration); 3 console.log('delay-->'+this.delay); 4 },this.delay);
那么问题就清楚了,函数实现中的this当然是指向window了,千万别被this.slidePic蒙骗。
既然this就是window,那么delay,duration这两个属性当然也就不存在了。
2.apply/call?
既然是作用域的问题,那么解决问题的关键也就是如何修改setInterval的作用域了。
修改函数作用域,我们的第一个方案当然就是apply/call了,我们按照理论尝试将代码修改如下:
autoPlay:function(){ //自动轮播图片 var self=this; setInterval(self.slidePic.apply(self),this.delay); }
我们将当前对象this传递给apply方法,看起来应该是OK的,运行后结果如下:
果然,结果出来了。
等等,好像有点不对!这个结果只打印了一次,并不是根据setInterval定时循环调用的。
换成了call结果也一样。
查了查这两个方法:apply/call如果用在setInterval中的话,只会立即运行一次,而不会按照我们的设想循环调用。
怎么办?
我们的主角出场了:bind。
call和apply是立即执行方法,而bind是产生一个新方法用于后续调用。
我们修改了下代码:
setInterval(self.slidePic.bind(self),this.delay);
果然我们想要的结果出现了:
3.匿名函数
还有没有别的办法?
其实在一开始的时候我们已经说了,给setInterval传递this.slidePic参数等价于:
1 setInterval(function(){
2 console.log('duration-->'+this.duration);
3 console.log('delay-->'+this.delay);
4 },this.delay);
这里我们定义了一个匿名函数作为参数setInterval的第一个参数,但是忽略了一点,
这个匿名函数中的this仍然指向window,所以这种做法当然也是不行。
那么我们只要将this换成我们的SlidePicture对象就可以了。
调整下代码:
autoPlay:function(){ //自动轮播图片 var self=this; // setInterval(self.slidePic.bind(self),this.delay); setInterval(function(){ self.slidePic(); },this.delay); }
在调用setInterval之前我们先将当前对象this保存下来,然后在匿名函数中调用了就OK了!
这也是处理this对象的一种常见方案。
------写得乱七八糟的,不管怎样希望对各位有所帮助-----
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?