1

闭包是javascript中绕不开的话题,关于闭包的一些概念和应用,这方面资料比较多,在此就不再赘述。众所周知,闭包的一个作用就是 让一些变量始终保持在内存中 ,在此我用一些实际代码对这句话作进一步的理解。

demo1:
    function closure(){
      var n = 0;
      function test() {
        console.log(++n);
      }
      test() 
      test() 
    }
    closure(); //输出1,2(这个很好理解,不多说)
demo2:
    function test(){
        var i=0;
        return function(){
            console.log(i++);
        }
        }
        var fn = test();
        fn(); //输出0
        fn(); //输出1

上述代码中,fn就是执行函数test()返回的匿名函数。由于fn又是一个全局变量,生命周期一直存在,且这个匿名函数引用了父函数test里面的一个局部变量,所以变量i的状态会被一直保存.

demo3:
    function test(){
        var i=0;
        return function(){
            console.log(i++);
        }
    }
    test()(); //输出0
    test()(); //输出0

上述代码中,执行test()返回的是其内部的匿名函数,但是执行完test()()以后,该匿名函数的生命周期已经结束,所以变量i的状态没有得到保存。

最近在简书上读到一篇有趣的文章,其中一些代码如下:

for (var i = 0; i < 5; i++) {
 setTimeout((function(i) {
    console.log(i);
  })(i), i * 1000);
}   //输出0,1,2,3,4

上述代码中有一个setTimeout()函数,其使用格式为setTimeout(func,time),意思是至少过time时间后,执行func。有了这样的认识后,我们可以把func等价成:
(function(i){console.log(i)})(i)这个自执行函数。所以这个事情分两步,首先每次循环自执行函数肯定会立即执行一次,会依次输出1,2,3,4。其次,每过time时间,执行一次func,但是在上述代码中,func等价于一个立即执行函数,没有返回值,故什么也不会做。
如果把上述代码改成这样:

for (var i = 0; i < 5; i++) {
  var j=7;
  setTimeout((function(i) {
    console.log(i);
    return function(){
       console.info(j++);
    }
  })(i), i * 1000);
}

上述代码会依次输出0,1,2,3,4, 7,8,9,10,11(结合这个例子理解上一个问题,就容易多了)

如果把上面的代码改成这样呢?

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 1000);
}

运行上面的代码会输出5个5(这一点现在可以理解了吧),有人不解的是为什么是每隔一秒输出5而不是隔五秒输出5。setTimeout(func,time)这个函数延迟执行的只是func里面的动作,而time的值是不存在延迟的。上面执行for循环,相当于:setTimeout(func,1000),setTimeout(func,2000) .... 第一次setTimeout执行的时候等了一秒(准确地说,至少要等一秒),第二次setTimeout执行的时候等2秒,但是前面第一次执行的setTimeout函数时,已经等了一秒,所以只需再等一秒就可以立即执行了。在这里,需要弄明白的是,setTimeout函数延迟执行的时间,起点是从time开始赋值的时候计算的,不是从上一个setTimeout函数执行完开始算的。


Zuckjet
437 声望657 粉丝

学如逆水行舟,不进则退。