• 修改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对象的一种常见方案。


     

       ------写得乱七八糟的,不管怎样希望对各位有所帮助-----

      

  • 相关阅读:
    在Salesforce中创建Approval Process
    用C#基于WCF创建TCP的Service供Client端调用
    用 C# 实现一个简单的 Rest Service 供外部调用
    在Salesforce中将 Decimal 数据转换成美元格式
    在Asp.Net MVC中PartialView与EditorFor和DisplayFor的区别
    在Salesforce中对某一个Object添加自定义的Button和Link
    【LeetCode】227. Basic Calculator II
    【LeetCode】226. Invert Binary Tree
    【LeetCode】225. Implement Stack using Queues
    【LeetCode】224. Basic Calculator
  • 原文地址:https://www.cnblogs.com/souvenir/p/4977407.html
Copyright © 2020-2023  润新知