关于闭包的理解

来源:互联网 发布:单片机简介 编辑:程序博客网 时间:2024/06/05 16:34

今天又看了一遍闭包的知识,感觉没看一次就会多一次理解,今天把自己看书所理解的东西写下来,做一个分享。希望批评指正。

要想理解闭包,必须先了解作用域以及作用环境。下面是自己列举的例子:






上面的代码显然会报错,因为在函数test中是访问不到函数add中的变量sum的,所以没办法弹出sum的值。这是因为js函数的作用域。在一些类C的编程语言中,每个花括号中的代码都有各自的作用域,在声明变量的作用域之外是没办法访问到变量的,称为块级作用域。
JS中没有块级作用域,取而代之的就是函数作用域。所以在上述代码中,因为作用域的限制,test函数访问不到add函数中的变量。
下面看一段代码,是经过处理后,访问到sum的值。
        


第一段代码是在函数add中添加一个立即执行的匿名函数,在匿名函数中弹出sum的值;第二段代码是返回一个匿名函数。这两种方法都成功的在匿名函数中获取到sum的值,即运用了闭包。根本原因是因为在匿名函数的作用域链中包含了外部函数add()的活动对象。
作用域链:在创建函数时,会创建一个作用域链。这个作用域链用决定哪些数据可以被访问,保存在内部的[[scope]]属性中。
在开始创建的作用域链中,会预先包含全局变量对象。当函数被调用的时候,为函数创建一个执行环境,然后通过复制【【scope】】属性中的对象来构建执行环境的作用域链。此后又有活动对象被创建,并且被推入作用域链的前端。
下面我画出针对后一段代码的作用域链:

我们知道,作用域链的前端始终是当前执行代码的变量对象(如果是函数则是活动对象),下一个变量对象则是来自外部环境,作用域链的最后一个对象始终是全局执行环境的变量对象。

闭包的性能问题:因为闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用会导致内存占用过多。

下面是关于作用域链的一个副作用(闭包只能取得包含函数中任何变量的最后一个值)
下面是我们经常遇到的一个栗子:
function test(){
    var result = new Array();
    for(var i = 0;i<10;i++){
        result[i] = function(){
                return i;
            }
        }
return result;
}
因为闭包所保存的是整个变量对象,而不是特殊的变量。所以上述每个函数中都保存着是test函数的活动对象,所以它们引用的都是同一个变量i,返回的都是10.

function test(){
    var result = new Array();
    for(var i = 0;i<10;i++){
        result[i] = function(){
                return function(num){
                    return num;
                };
            }(i);
        }
return result;
}



0 0