美文网首页
03 JS 闭包

03 JS 闭包

作者: Android_小生 | 来源:发表于2019-07-15 21:22 被阅读0次

    1.概念

    闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

    2.示例说明

    有关如何创建作用域链以及作用域链有什么作用的细节,对彻底理解闭包至关重要。

    // 代码示例 1
    function createComparisonFunction(propertyName) {
        return function(object1, object2) {
            let value1 = object1[propertyName];
            let value2 = object2[propertyName];
            
            if(value1 < value2) {
                return -1;
            } else if(value1 > value2) {
                return 1;
            } else {
                return 0;
            }
        }
    }
    
    // 创建函数
    let compareNames = createComparisonFunction('name');
    // undefined
    // 调用函数
    let result = compareNames({name: 'Zhang'}, {name: 'Li'});
    
    // 调用函数
    let out = compareNames({name: 'Zhang'}, {name: 'Li'});
    // undefined
    out;
    // 1
    

    分析上述示例 1 代码:

    在匿名函数从 createComparisonFunction() 函数中被返回后,它的作用域链被初始化为包含 createComparisonFunction() 函数的活动对象和全局变量对象。createComparisonFunction() 函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。换句话说,当 createComparisonFunction() 函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中,直到匿名函数被销毁后,createComparisonFunction() 的活动对象才会被销毁。

    闭包

    由于闭包会携带包含其它的函数的作用域,因此会比其它函数占用更多的内存。 慎重使用闭包。

    3.闭包与变量

    作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊的变量。

    // 代码示例 2
    function createFunction() {
        let result = new Array();
    
        for(var i = 0; i < 10; i++) {
            result[i] = function() {
                return i;
            }
        }
        return result;
    }
    

    上述代码示例 2 中,每个匿名函数的作用域链中都保存着 createFunction() 函数的活动对象,所以它们引用的都是同一个 i。当 createFunction() 函数返回后,变量 i 的值是 10,而每个函数都引用着保存变量 i 的同一个变量对象,每个函数内部 i 的值都是 10。

    // 代码示例 3
    function createFunction() {
        let result = new Array();
    
        for(let i = 0; i < 10; i++) {
            result[i] = function(num) {
                return function() {
                    return num;
                }
            }(i);
        }
        return result;
    }
    

    代码示例 3 中,通过创建另一个匿名函数强制让闭包的行为符合预期。在调用每个匿名函数时,我们传入了变量 i,由于函数参数是按值传递的,所以就会将变量 i 的当前值复制给参数 num。而这个匿名函数内部,又创建并返回了 num 的闭包。这样一来, result 数组中的每个函数都有自己 num 变量的一个副本,因此可以返回各自不同的副本。

    总结

    闭包,就是在一个函数内部创建另一个函数。里面函数的作用域链中引用了外部函数的活动对象,外部函数调用执行完成时,外部函数的作用域链会销毁,而因为里面函数的作用域链中引用了外部函数的活动对象,只有在里面函数的执行环境销毁后,外部函数的活动对象才你销毁。使用过多闭包会使内存占用过多。

    对于闭包的情况,闭包函数只有获取包含函数中任何变量的最后一个值。我们可以通过在匿名函数再次将闭包函数包裹起来,而闭包参数的引用通过匿名函数引用包含函数的值传递给参数。

    注:文章参考总结自 《JavaScript 高级程序设计》(第 3 版)[美] Nicholas C.Zakas 著 第 178 页。

    相关文章

      网友评论

          本文标题:03 JS 闭包

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