js整理四:闭包[转载多]

闭包

很多是参考了一篇文章==可不幸忘记源地址了。对不住源作者了,如果看到请高手我,我好修正,谢谢

##4.1关于js中的作用域链##
在博客上看到的理解:
(1)首先是JavaScript引擎可以访问的一个内部的属性[scope],里面保存的是函数被创建的时作用域中对象的集合,也被称为函数的作用域链,它决定了那些数据可以被函数访问。

(2)然后再来介绍下,一个函数创建的过程。当一个函数被创建后,它的作用域链会被创建该函数的作用域中可以访问的数据对象填充,例如

function add(num1,num2){
    var sum= num1 + num2;
    return sum;
}

在函数add创建的时候,他的作用域链中会填入一个全局的对象,包含了所有的全局的变量

pic1

(3) 接着当该函数在被执行的时候
var total= add(5,10);
执行此函数时会创建一个称为“运行期上下文(execution context)”的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。
这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:
pic2

在函数执行过程中,没遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取和存储数据。该过程从作用域链头部,也就是从活动对象开始搜索,查找同名的标识符,如果找到了就使用这个标识符对应的变量,如果没找到继续搜索作用域链中的下一个对象,如果搜索完所有对象都未找到,则认为该标识符未定义。函数执行过程中,每个标识符都要经历这样的搜索过程。

//JS高级
当调用函数的时候,会被函数创建一个执行环境,然后通过赋值函数的内部属性[[scope]]]中的对象构建起的执行环境的作用域链。

(4)关于函数内部嵌套的问题
如果在一个函数A内部再定义了一个函数B,那么在函数B的作用域链中会将函数A(外部函数)的活动对象添加到B的作用域链中去,

##4.2关于闭包##

在阮一峰的博客中提到了闭包的两个用途,分别如下:
(1)可以读取函数内部的变量;
(2)让这些变量的值始终保持在内存中
注(貌似在其他的博客上看到过闭包的另外一个用途就是当你要声明一个私有变量的时候,你可以利用闭包的特性使外部对象不能访问这个变量,就是类似private的感觉)

闭包的注意点:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

//—————————分割线———————————–
个人对闭包的理解:先看一小段代码

function A (){
    var i = 0 ;
    var B =function (){
        console.log(i);
    }
    return B;
}

很简短的一段,我理解的闭包就是上诉代码中,在一个函数中返回了内部定义的一个函数,这样的作用是什么呢?正常的情况下,一个函数结束后,他内部定义的变量什么的会被回收掉,但是有了这个闭包的东西就会出现例外,用到前面讲到的那个作用域链的理论来解释下,B的scope chain中有着函数A的活动对象,正是由于这点,函数B可以使用读取变量i的数值,现在这种情况下,当函数阶数后,返回了函数B,那么B就被引用着,所以他不会被回收这点毫无疑问,然后看A,A活动对象中的i变量现在被B引用着,所以他的活动对象会留着没被回收,以上都是个人的一点理解不知道对不对,若有不对的地方,希望能指出~

##4.3闭包与变量##
在js高级程序设计中提到了有关这个的问题
(1)问题的引出:代码如下

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

原本预期应该觉得输出的是0到9之间的数字保存在result之中,但是实际上,里面保存的值都是10;理解的方式就是每个函数的作用域链中都保存着createFunctions函数的活动对象,所以他们引用的是同一个i对象

注(可以这么理解,想象一下一共有十个函数在createFunctions里声明着,名字分别可以是result[0]等等的,然后在他们的scope链中都有这么一个指针指向他们的上级函数就是createFunctions的活动对象,里面有变量i,他们是指向同一个活动对象的,所以他们共享着这个i)
//——————分割线—————————————–
不过有方法可以强制改变这种情况,具体如下

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

现在这种情况呢,就不会出现内部的函数还一直占有函数createFunctions活动对象的情况了。