美文网首页
JavaScript 闭包、定时器

JavaScript 闭包、定时器

作者: 柯良勇 | 来源:发表于2016-05-25 15:35 被阅读105次

    闭包及其作用

    • 闭包是能够读取其他函数内部变量的函数;相当于在草原上用栅栏单独围一片地只留一个进出口;只有通过返回出的函数才能去修改其内部的变量。
    • 有两个作用:①读取/修改其他函数内部的变量,形成单独的一个空间,不受外部影响,可用于封装。②使其他函数内部的变量不会被销毁而始终存在于内存中。

    setTimeout 0 的作用

    • setTimeout 0 的作用并不在于其延时0的这个字面意思,而是js对它的处理机制上;对被setTimeout包裹的代码段,不管其延时多久,都会被js放到代码的尾部,只有等其他代码执行完毕后才会按延时时间去运行其内部的代码;
    • 根据这个特性,我们可以把需要最后执行的代码用setTimeout 0进行包裹,确保最后执行;在部分事件上,例如我需要一个div显示用户输入文本框的内容,这个时候我使用onkeydown来绑定更新输入值,当键盘被按下时开始更新输入值;但是第一次按下键盘输入时,此时js的处理结果还没出来,但由于我绑定按下这个条件就会更新输入值,所以等于第一次输入去获取更新时是空的,这样在用户看来就是我按下第二个键才显示之前输入的内容;那么我们可以怎么做呢?对,在获取更新的这个代码上加setTimeout 0 ,让其跑到js处理结果之后去更新,这样就能实时显示输入值了!

    小练习

    下面的代码输出多少?修改代码让fnArri 输出 i

    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        fnArr[i] =  function(){
            return i;
        };
    }
    console.log( fnArr[3]() );  //  输出为10
    

    方法1 使用闭包:

    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        fnArr[i] =  function(i){
            return function(){
              return i;
            };
        }(i);
    }
    console.log( fnArr[2]() );  //  2
    

    方法2 把i绑定到函数上 作为函数的一个属性存储起来

    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
      var print=function(){};
      print.index=i;
      fnArr[i]=print;
    
    }
    console.log( fnArr[5].index );  //  5
    

    方法3 用两个立即执行函数返回i 赋给fnArr[i];相当于fnArr[i]=i,数组里面放的是固定的数(好像没什么。。。但是fnArr[i]可以输出i)

    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        fnArr[i] =  function(){
            return function(){
              return i;
            }();
        }();
    }
    console.log( fnArr[7] );  //  7
    

    使用闭包封装一个car对象

    var Car = function(){
      var speed=0;
      return{
        setSpeed:function (num){
          speed=num;
        },
        getSpeed:function (){
          console.log(speed);
        },
        accelerate:function (){
          speed=speed+10;
        },
        decelerate:function (){
          speed=speed-10;
        },
        getStatus:function (){
          if(speed>0)
            console.log('running')
          else console.log('stop')
        }
      }
    }();
    Car.setSpeed(30);
    Car.getSpeed(); //30
    Car.accelerate();
    Car.getSpeed(); //40;
    Car.decelerate();
    Car.decelerate();
    Car.getSpeed(); //20
    Car.getStatus(); // 'running';
    Car.decelerate(); 
    Car.decelerate();
    Car.getStatus();  //'stop';
    //Car.speed;  //error
    

    使用setTimeout模拟setInterval的功能

    function newInterval(func,time){  //定义伪间隔函数  一个形参为‘函数’,另一个形参为‘间隔时间’
      setTimeout(function(){
        func();
        newInterval(func,time);
      },time);
    }
    var i=1;
    function count(){      //举个例子 使用计数函数 
      console.log(i++);
    }
    newInterval(count,1000);
    

    计算setTimeout最小时间粒度

    function min(){
      var t1=Date.now();
      var i=0;
      var clock=setTimeout(function(){
        i++;
        if (i==5000){
          clearInterval(clock);
          console.log((Date.now()-t1)/i);
        }
        clock=setTimeout(arguments.callee,0)
      },0);
    }
    min();  //  4.102  4.0982  4.0968  最小粒度应该为4ms 
    

    解释如下代码的输出

    var flag = true;
    setTimeout(function(){
        flag = false;
    },0)
    while(flag){}   //没有输出结果 因为setTimeout所包裹的代码将会被放到末尾执行 flag一直是true 导致循环一直在进行,后面的代码在排队等候中
    console.log(flag); 
    

    下面这段代码输出?如何输出delayer: 0, delayer:1...(使用闭包来实现)

    for(var i=0;i<5;i++){
        setTimeout(function(){
             console.log('delayer:' + i );  // 
        }, 0);
        console.log(i);    // 先输出 0  1  2  3  4 ,再输出 delayer:5
    }
    

    让其输出delayer: 0, delayer:1的方法如下:

    for(var i=0;i<5;i++){
      (function(i){
        setTimeout(function(){
          console.log('delayer:' + i );
        }, 0);
        console.log(i);   //先输出 0  1  2  3   4 再输出 delayer:0 delayer:1 delayer:2 delayer:3 delayer:4
      })(i);                    
    }

    相关文章

      网友评论

          本文标题:JavaScript 闭包、定时器

          本文链接:https://www.haomeiwen.com/subject/ypjtdttx.html