美文网首页
2018-12-04

2018-12-04

作者: kathyever | 来源:发表于2018-12-04 14:18 被阅读0次

    再次复习一下闭包

    什么是闭包?

    闭包可以简单理解成“定义在一个函数内部的函数“,有权访问另一个函数作用域内变量的函数都是闭包。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

    通过一个例子来看闭包:

    function a(){
        var i=0;
        function b(){
            alert(++i);
        }
        return b;
    }
    var c=a();
    c();
    

    这段代码有两个特点:
    1、函数b嵌套在函数a内部;
    2、函数a返回函数b。

    这样在执行完var c=a( )后,变量c实际上是指向了函数b,再执行c( )后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,这是因为函数a外的变量c引用了函数a内的函数b。也就是说,当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。


    再来看一个例子:

    例1:

    function a(){
        var n = 0;
        function inc() {
            n++;
            console.log(n);
        }
        inc();  
        inc(); 
    }
    a(); //控制台输出1,再输出2
    

    例2:

    function a(){
        var n = 0;
        this.inc = function () {
            n++; 
            console.log(n);
        };
    }
    var c = new a();
    c.inc();    //控制台输出1
    c.inc();    //控制台输出2
    

    我们知道,js的每个函数都是一个个小黑屋,它可以获取外界信息,但是外界却无法直接看到里面的内容。将变量 n 放进小黑屋里,除了 inc 函数之外,没有其他办法能接触到变量 n,而且在函数 a 外定义同名的变量 n 也是互不影响的,这就是所谓的增强“封装性”。

    而之所以要用 return 返回函数标识 inc,是因为在 a 函数外部无法直接调用 inc 函数,所以 return inc 与外部联系起来,例 2 中的 this 也是将 inc 与外部联系起来而已。

    常见陷阱

    function createFunctions(){
        var result = new Array();
        for (var i=0; i < 10; i++){
            result[i] = function(){
                return i;
            };
        }
        return result;
    }
    var funcs = createFunctions();
    for (var i=0; i < funcs.length; i++){
        console.log(funcs[i]());
    }
    

    乍一看,以为输出 0~9 ,万万没想到输出10个10?
    这里的陷阱就是:函数带()才是执行函数!单纯的一句 var f = function() { alert('Hi'); }; 是不会弹窗的,后面接一句 f(); 才会执行函数内部的代码。

    将上面的代码翻译成下面的代码:

    var result = new Array(), i;
    result[0] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
    result[1] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
    ...
    result[9] = function(){ return i; }; //没执行函数,函数内部不变,不能将函数内的i替换!
    i = 10;
    funcs = result;
    result = null;
    
    console.log(i); // funcs[0]()就是执行 return i 语句,就是返回10
    console.log(i); // funcs[1]()就是执行 return i 语句,就是返回10
    ...
    console.log(i); // funcs[9]()就是执行 return i 语句,就是返回10
    

    (为什么只垃圾回收了 result,但却不收了 i 呢? 因为 i 还在被 function 引用着啊。好比一个餐厅,盘子总是有限的,所以服务员会去巡台回收空盘子,但还装着菜的盘子他怎么敢收? 当然,你自己手动倒掉了盘子里面的菜(=null),那盘子就会被收走了,这就是所谓的内存回收机制。

    至于 i 的值怎么还能保留,其实从文章开头一路读下来,这应该没有什么可以纠结的地方。盘子里面的菜,吃了一块不就应该少一块吗?)

    太喜欢这个解释了,通俗易懂!

    闭包可以用在许多地方。它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中,不会在f1调用后被自动清除。

    相关文章

      网友评论

          本文标题:2018-12-04

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