掘金评论:本质就是上级作用域内变量的生命周期,因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放

    任何闭包的使用场景都离不开这两点:

    • 创建私有变量
    • 延长变量的生命周期

    一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的

    举个例子:

    1. var data = [];
    2. for (var i = 0; i < 3; i++) {
    3. data[i] = function () {
    4. console.log(i);
    5. };
    6. }
    7. data[0]();
    8. data[1]();
    9. data[2]();
    10. // 3 3 3

    当执行到data0的时候,上面的for循环已经执行完成了,i是全局变量这个时候打印的i已经是3了。
    data[0]其实就是一个打印 i 的函数

    1. for (var i = 0; i < 3; i++) {}
    2. console.log(i) // 3

    再看看闭包版本

    1. var data = [];
    2. for (var i = 0; i < 3; i++) {
    3. data[i] = (function (i) {
    4. return function(){
    5. console.log(i);
    6. }
    7. })(i);
    8. }
    9. data[0]();
    10. data[1]();
    11. data[2]();
    12. // 1 2 3

    下面是个人理解

    1. var data = [];
    2. for (var i = 0; i < 3; i++) {
    3. data[i] = (function (i) {
    4. return function(){
    5. console.log(i);
    6. }
    7. })(i);
    8. }
    9. data[0]();
    10. data[1]();
    11. data[2]();
    12. // 这时候data[0]就相当于
    13. (function (i) {
    14. // 这里的i是0
    15. return function(){
    16. console.log(i);
    17. }
    18. })(0)
    19. // 实际上这里应该有两个i 一个是for循环的时候 用var 声明的全局变量i这个i的值等于3,也就是第一段函数的例子当函数执行console.log(i);只有全局作用域找到了全局变量i,这个i等于3 所以输出的值是3
    20. // 第二个i是自执行函数内部的i,在data[0]的时候因为当时循环传的参数是0,所以自执行函数内部的i也是0,当执行console.log(i);时向上查找i先遇到的是自执行函数的函数作用域,这里的i等于0,就直接打印了0,当然在这个时候外部全局变量的i也是3,只是因为被函数作用域的i截胡了所以没有打印3
    21. // data[1] data[2] 同理