setTimeout和setInterval中使用this

JavaScript代码

  1. var roll = function(objid, step, direct)  

其中objid为要滚动的容器ID,step为每一轮滚动的距离,direct为滚动方向。基础结构和一些方法就不去管了,直接进入关键点。

roll类的主要方法(都通过prototype设置)有:

initroll(); //初始化滚动
playroll(); //开始滚动
stoproll(); //停止滚动
rollPlaying(); //滚动处理
rollReset(); //重置滚动内容

可以看出,我的设想是,创建滚动版只需要:

JavaScript代码
  1. var imgroll = new roll('rollImages', 120, 'TOP');   
  2. imgroll.initroll();  

这里已经在创建实例的时候初始化了,为什么还要initroll呢?因为我想,滚动动作并不是加载后立即执行的,而是在设定的几秒时间后,所以在initroll()中的最重要的内容便是:

JavaScript代码
  1. roll.prototype.initroll = function(){   
  2.     this.objtimeout = setTimeout(this.playroll, this.iResume);   
  3. }  

有经验的人可能看出了这里的问题,可是我却一点都没有发觉,这里记录一下问题一

playroll(),stoproll()都只是开关来控制rollPlaying(),他们的内容分别是:

JavaScript代码
  1. roll.prototype.playroll = function(){   
  2.     this.objrolling = setInterval(this.rollPlaying, this.iTime);   
  3. }  
JavaScript代码
  1. roll.prototype.stoproll = function(){   
  2.      clearTimeout(this.objtimeout);   
  3.      clearInterval(this.objrolling);   
  4. }  

这里playroll()出了和上面一样的问题记录问题二

rollPlaying()中的滚动处理本身并没有什么问题,但是因为上面出现的错误而导致了运行出错。那么问题在哪里呢?

问题一:setTimeout(func, time)里面的func我使用了this关键字,来标识是类实例的方法,至少我个人一直认为是这样的,func参数中使用this关键字本身并没有问题, 可以正确在time时间后执行playroll(),可是在playroll()里面就碰到了问题二。(可能有人会说,你的setTimeout的func参数没有带括号,实事证明有括号的情况比没有更惨烈。。。)

问题二:可见我在playroll()中使用了大量的this关键字来标识roll类实例的元素或方法,但是因为问题一是在setTimeout中使用playroll()这个方法,因此这里的this已经不是我设想的类实例的this关键字了。我至今还没有弄明白在前面的setTimeout中使用this关键字的方法导致了playroll中的this变成了什么,总而言之这个this已经不是roll的一个实例了。前面也说playroll()中的错误和initroll()中的错误一样,同样导致了rollPlaying()中的this关键字失效。

解决问题的方法应该有两个:其一是不使用this关键字而用其他的方式替代(因为我觉得太麻烦而且会破坏结构于是放弃了);其二是我现在用的解决方案,如下:

JavaScript代码
  1. roll.prototype.initroll = function(){   
  2.     var o = this;   
  3.     this.objtimeout = setTimeout(function(){o.playroll(o)}, this.iResume);   
  4. }  
JavaScript代码
  1. roll.prototype.playroll = function(o){   
  2.     this.objrolling = setInterval(function(){o.rollPlaying();}, this.iTime);   
  3. }  

我在initroll()中创建了一个变量o为this本身,再使用匿名方法把o作为实例本身,也作为参数传递给了playroll(),为什么要既作为实例本身又作为参数呢?作为实例的作用是可以在playroll()中使用this关键字,而作为参数是为了在playroll()当中不用再为setInterval重新申明一个实例。

有人可能会说,为什么不setTimeout(function(){this.playroll()}, this.iResume)呢?这样显然不行的原因连试都不用试了,因为这样的情况下匿名方法内的this关键字变成了匿名方法本身而不是外部类,所以才需要一个变量来处理,或者可以看作一个闭包,在initroll结束之后o变量的作用域仍然存在。

为了这个问题绕了一些弯路,觉得应该记录一下,以备后患。

你可能感兴趣的:(setTimeout和setInterval中使用this)