JS的闭包

闭包是一个比较抽象的概念,尤为是对js新手来讲.书上的解释实在是比较晦涩,对我来讲也是同样.程序员

  闭包是不少语言都具有的特性,在js中,闭包主要涉及到js的几个其余的特性:做用域链,垃圾(内存)回收机制,函数嵌套,等等.闭包

  在理解闭包之前.最好能先理解一下做用域链的含义,简单来讲,做用域链就是函数在定义的时候建立的,用于寻找使用到的变量的值的一个索引,而他 内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函 数中须要查询一个变量的值的时候,js解释器会去做用域链去查找,从最前面的本地变量中先找,若是没有找到对应的变量,则到下一级的链上找,一旦找到了变 量,则再也不继续.若是找到最后也没找到须要的变量,则解释器返回undefined.函数

  了解了做用域链,咱们再来看看js的内存回收机制,通常来讲,一个函数在执行开始的时候,会给其中定义的变量划份内存空间保存,以备后面的语句 所用,等到函数执行完毕返回了,这些变量就被认为是无用的了.对应的内存空间也就被回收了.下次再执行此函数的时候,全部的变量又回到最初的状态,从新赋 值使用.可是若是这个函数内部又嵌套了另外一个函数,而这个函数是有可能在外部被调用到的.而且这个内部函数又使用了外部函数的某些变量的话.这种内存回收 机制就会出现问题.若是在外部函数返回后,又直接调用了内部函数,那么内部函数就没法读取到他所须要的外部函数中变量的值了.因此js解释器在遇到函数定 义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一块儿保存起来.也就是构建一个闭包,这些变量将不会被内 存回收器所回收,只有当内部的函数不可能被调用之后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存 回收启动时所回收.spa

也就是说,有了闭包,嵌套的函数结构才能够运做,这也是符合咱们的预期的.而后,闭包还有一些特性,却每每让程序员以为很难理解..net

    看看下面一段代码:
指针

?code

1
2
3
4
5
6
7
8
9
10
11
12
13
var  result=[];
function  foo(){
     var  i= 0;
     for  (;i<3;i=i+1){
         result[i]= function (){
             alert(i)
         }
     }
};
foo();
result[0]();  // 3
result[1]();  // 3
result[2]();  // 3

    这段代码中,程序员但愿foo函数中的变量i被内部循环的函数使用,而且能分别得到他们的索引,而实际上,只能得到该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.orm

解决的方法之一,是让内部函数在循环建立的时候当即执行,而且捕捉当前的索引值,而后记录在本身的一个本地变量里.而后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值,改进后的代码:对象

?blog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var  result=[];
function  foo(){
     var  i= 0;
     for  (;i<3;i=i+1){
         result[i]=( function (j){
             return  function (){
                 alert(j);
             };
         })(i);
     }
};
foo();
result[0]();  // 0
result[1]();  // 1
result[2]();  // 2
相关文章
相关标签/搜索