闭包是一个比较抽象的概念,尤为是对js新手来讲.书上的解释实在是比较晦涩,对我来讲也是同样.html
可是他也是js能力提高中没法绕过的一环,几乎每次面试必问的问题,由于在回答的时候.你的答案的深度,对术语的理解以及js内部解释器的运做方式的描述,都是能够看出你js实际水平的.即便你没答对,也能让考官对你的水平有个评估.那么我先来讲说我对js中的闭包的理解.程序员
闭包是不少语言都具有的特性,在js中,闭包主要涉及到js的几个其余的特性:做用域链,垃圾(内存)回收机制,函数嵌套,等等.面试
在理解闭包之前.最好能先理解一下做用域链的含义,简单来讲,做用域链就是函数在定义的时候建立的,用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函数中须要查询一个变量的值的时候,js解释器会去做用域链去查找,从最前面的本地变量中先找,若是没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则再也不继续.若是找到最后也没找到须要的变量,则解释器返回undefined.闭包
了解了做用域链,咱们再来看看js的内存回收机制,通常来讲,一个函数在执行开始的时候,会给其中定义的变量划份内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了.对应的内存空间也就被回收了.下次再执行此函数的时候,全部的变量又回到最初的状态,从新赋值使用.可是若是这个函数内部又嵌套了另外一个函数,而这个函数是有可能在外部被调用到的.而且这个内部函数又使用了外部函数的某些变量的话.这种内存回收机制就会出现问题.若是在外部函数返回后,又直接调用了内部函数,那么内部函数就没法读取到他所须要的外部函数中变量的值了.因此js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一块儿保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用之后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收.函数
也就是说,有了闭包,嵌套的函数结构才能够运做,这也是符合咱们的预期的.而后,闭包还有一些特性,却每每让程序员以为很难理解.spa
看看下面一段代码.指针
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被内部循环的函数使用,而且能分别得到他们的索引,而实际上,只能得到该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.code
解决的方法之一,是让内部函数在循环建立的时候当即执行,而且捕捉当前的索引值,而后记录在本身的一个本地变量里.而后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值,改进后的代码:htm
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
在这里我再解释一下.这里用到了另外2个技术,当即调用的匿名函数和返回函数.也是初学者比较难以理解的部分.对象
转自
:http://www.cnblogs.com/mzwr1982/archive/2012/05/20/2509295.html