JavaScript之闭包、定时器

谈谈闭包

对于JavaScript而言,虽然没有块作用域的概念,但是有函数作用域的概念,若是想从全局环境下去访问一个函数内的局部变量,是办不到的;但是根据JavaScript中的链式作用域的概念,它是可以访问外面的全局变量的,所以,针对一个被定义在函数内的函数,它的父函数中的所有变量也是能够被它访问到的。

  1. 什么是闭包
    闭包(Closure)是让内部函数能够访问外部函数中的变量。
    一个最简单的闭包栗子:

    function Closure{
     var a = 1;// 在最父函数环境中定义了a
     return function(){
       a = 2;   // 给a赋值,但是在当前作用域中并没有声明a这个变量
     }
    }
    func = Closure(); // 这时的返回值即是一个函数
    func() // 对里面的函数进行调用,这时a的值发生了改变
  2. 闭包的作用
    闭包的作用就是让内部函数能够访问到外部变量,就像上面例子中所演示的样子。
    闭包的另一个作用就是让一些变量始终保存在内存中,看下面:

    
    function func(){
     var a = 1;
     function add(){
       a++;
     }
     function ret(){
       return a;
     }
     return {
       ret:ret,
       add:add
     }
    }
    var f1 = func();
    f1.add();
    f1.add();
    console.log(f1.ret());

    在这个栗子中,函数中的子函数add一共运行了两次,将a的值从1改变到了3,由于父函数被赋给了一个全局变量,所以它就一直在内存中,而不是在调用之后被自动清除了。

  3. 使用闭包的注意点
    上文中已经说过,闭包的特点之一,也是最主要的特点就是函数的所有变量都会被保存在内存中,那么这些变量当然也会占用内存,如果闭包使用过度甚至滥用,就会给内存造成很大的负担,可能会造成性能问题甚至造成内存泄漏,所以在使用完成闭包之后一定要手动去清除这块内存,避免内存问题的出现。

    setTimeout 0 有什么作用

    但从字面上的意思来看,这样设置就是让函数延迟0s执行,但是其实不然,它的作用是让函数放到最后去执行,比如:
    setTimeout(function(){console.log(1);},0); (function(){console.log(12);}());
    以上两个函数的执行顺序并不是按照顺序上的先打印1,再打印12;由于给前面的函数设置了0s的延时,执行到此处的时候它就被放进了循环队列,遵循队列后进后出的原理,在执行完成其它代码后再对队列中的代码依次执行。

    下面代码的输出是什么,对其进行修改让fnArr()输出i,使用2种以上的方式

    
     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(){
             return i;
         }(i);
     }
     console.log( fnArr[3] );  //

    修改二:

    
     for(var i=0;i<5;i++){
       (function(){
         var n = i;
         setTimeout(function(){
              console.log('delayer:' + n );
         }, 0);
       })();
    
         console.log(i);
     }

使用闭包封装汽车对象,并获取状态


    var Car = carSet();
    function carSet(){
      var speed = 0;
      function setSpeed(spe){
        speed = spe;
      }
      function getSpeed(){
        console.log(speed);
        return speed;
      }
      function accelerate(){
        speed += 10;
      }
      function decelerate(){
        speed -= 10;
      }
      function getStatus(){
        if(speed === 0){
          console.log("stop");
          return "stop";
        }else{
          console.log("running");
          return "running";
        }
      }
      return{
        setSpeed:setSpeed,
        getSpeed:getSpeed,
        decelerate:decelerate,
        getStatus:getStatus,
        accelerate:accelerate
      }
    }
    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

使用setTimeot模拟setInterval的功能。


    function getsec(){
      setTimeout(function(){
        console.log(new Date().getSeconds());
        getsec();
      },1000)
    }

计算setTimeout的最小时间粒度


    function cTime(){
      var i = 0;
      var sta = Date.now();
      var clo = setTimeout(function a(){
        i++;
        if(i === 1000){
          var end = Date.now();
          clearTimeout(clo);
          console.log((end - sta)/i);
        }
      clo = setTimeout(a,0);
      },0);
    }
    cTime();

下列代码的输出


// 由于被设置延时的函数会被移动到队列中,等待所有正常执行完成之后再进行执行,所以执行的实际顺序为:
var a = 1;
var a;
console.log(a);   // 1
a = 3;
console.log(a);  // 3
setTimeout(function(){
  a = 2;
  console.log(a);
},0)

以下代码的输出


    var flag = true;
    setTimeout(function(){ // 设置延时后,这段代码被放进队列中,等待所有执行完成之后再执行
        flag = false;
    },0)
    while(flag){}  // 到这里的时候,判断flag一直会使true,无法往下执行,形成死循环
    console.log(flag);

以上代码在模拟控制台上会输出true,但实际只是假象

使用闭包来让下面这段函数输出delayer: 0, delayer:1...


for(var i=0;i<5;i++){
  (function(){
    var n = i;
    setTimeout(function(){
         console.log('delayer:' + n );
    }, 0);
  })();

    console.log(i);
}

大爷,请赏我点铜板买喵粮自己吃,您的支持将鼓励我继续创作!(支付宝)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值