打老壳的闭包知识

猜猜下面代码输出什么?

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

我猜不到啊。。。然后就从一个大神那儿学习了。

答案是:

分析:

由于setTimeout()实现异步的机制,代码console.log(i,'b');被指定到1s后执行,程序会先执行完console.log(i,'c');console.log(i,'a');等他们执行完后再执行console.log(i,'b');

一、首先,要知道setTimeout()的运行机制:

setTimeout运行机制

setTimeout()和setInterval()的运行机制是,将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。这意味着,setTimeout()指定的代码,必须等到本次执行的所有代码都执行完,才会执行。

Event Loop

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环);

举栗子:

test1();
setTimeout(otherTest,1000);
test2();

其中test1和test2为立即执行任务,otherTest被setTimeout()定时器指定在1s后执行,此时otherTest被添加到任务队列的尾部,要等当前的脚本中Event Loop的任务队列全部执行完成后,才开始执行otherTest,但如果test1和test2耗时很长,前面的任务超过1s还未结束,此时otherTest只能等test1和test2运行结束,才会执行otherTest。

console.log(1);
setTimeout(function(){console.log(2);},1000);//如果将setTimeout()的第二个参数设为0,就表示当前代码执行完(执行栈清空)以后,立即执行(0毫秒间隔)指定的回调函数。
console.log(3);

上面代码的执行结果是1,3,2,因为setTimeout()将第二行推迟到1000毫秒之后执行。

setTimeout(function(){console.log(1);}, 0);
console.log(2);

上面代码的执行结果总是2,1,因为只有在执行完第二行以后,系统才会去执行"任务队列"中的回调函数。

二、什么是闭包?

内部函数访问外部变量,内部函数被外部函数调用。通俗的讲就是函数a的内部函数b,被函数a外部的一个变量引用的时候,就创建了一个闭包。

函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。

栗子:

function f1(){
  var n=999;
}
alert(n); // error

将最开始的例子代码改为:

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

输出的结果为:5 -> 0,1,2,3,4 (使用了立即函数声明)

闭包的特性:

①.封闭性:外界无法访问闭包内部的数据,如果在闭包内声明变量,外界是无法访问的,除非闭包主动向外界提供访问接口;
②.持久性:一般的函数,调用完毕之后,系统自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在
系统中,闭包中的数据依然存在,从而实现对数据的持久使用。

优点:

① 减少全局变量。

② 减少传递函数的参数量

③ 封装;

缺点:
使用闭包会占有内存资源,过多的使用闭包会导致内存溢出等.

原文地址:https://www.cnblogs.com/wgl0126/p/9154689.html