闭包的概念比较抽象,理解起来比较困难,但是仔细分析一下其实也没有特别恐怖,面向对象的概念都搞定了这又算啥呢
定义:简单的说就是定义在函数内部的函数,具有读取局部变量的能力
从这个概念上可以看出闭包涉及到的js概念有:作用域链(局部变量) / 函数的嵌套(定义在函数内部的函数)/内存回收(这个比较难理解)
作用域链
作用域链是函数声明的时候创建的,用于寻找使用到的变量的值的一个索引,他内部的规则是,把自己函数内部的变量放在最前面优先读取,把父级函数的内部变量放在其次,然后依次向上排列,直到全局变量,
如果在子函数内部使用一个变量,如果自己函数内部没有,则去父级函数内寻找,依次向上,如果函数内部没有则查看全局变量,全局变量如果也没有则只为undefine,如果找到了则停止寻找;
var a =0;
function fun1(){
var a=1;
function fun2(){
var a=2;
alert(a);
}
fun2()
}
fun1() //-->2
内存回收
函数运行的时候会为函数内部声明的变量创建内存空间,以备后面的语句调用,函数运行结束后则认为这些变量已经使用完毕,于是变量被销毁,再次执行的时候则内存重新创建;
如果函数的内部又嵌套了另一个函数,而且这个函数有可能在外部被调用到,还用到了外部函数的一些变量上面提到的内存回收机制就会失效,也就是说内存不在回收了,
如果外部的函数调用后又直接调用了内部函数,如果按之前的内存回收的话,内部函数就无法读区到外部函数的变量的值了,这时候js解释器在遇到这种情况时就会把外部的函数保存起来以保证自己内部的变量不被回收,从而能保证内部的函数能够正常的调用,其实这种情况就形成了一个闭包,如果内部的函数被销毁,或者没有调用的可能性后闭包也就被回收了;
var test = [];
var i= 0;
for (;i<3;i=i+1){
test[i]=function(){
alert(i)
}
}
test[0] //3
test[1] //3
test[2] //3
闭包:
var test = [];
var i= 0;
for (;i<3;i=i+1){
test[i]=(function(j){
alert(j)
})(i)
}
test[0] //0
test[1] //1
test[2] //2
test实际上就是闭包fun2函数。它一共运行了两次,第一次的值是9,第二次的值是10。这证明了,函数fun1中的局部变量n一直保存在内存中,并没有在fun1调用后被自动清除,原因就在于fun1是fun2的父函数,而fun2被赋给了一个全局变量,这导致fun2始终在内存中,而fun2的存在依赖于fun1,因此fun1也始终在内存中,不会在调用结束后,被内存回收机制(garbage collection)回收
function fun1(){
var n=9;
add=function(){n+=1}//这里的add是一个全局变量,相当于fun1函数的setter方法,也是一个闭包
function fun2(){
alert(n);
}
return fun2;
}
var test=fun1();
test(); // 9
add();
test(); // 10
网友评论