JavaScript 闭包篇
1:闭包
(1)先来看个例子 :
function a(){
function b(){
var bbb = 234;
console.log(aaa);
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();
解析:我们来看这个例子,简便的分析一下,在全局有一个函数 a,变量 glob、demo, 然后 a 执行,执行前 a 的作用域链里放的是 a 的 AO 和 GO,然后在 a 函数里有一个函数 b 和变量 aaa,b 函数最开始拿的是 a 的劳动成果(a 的 AO 和 GO),但是最重要的是,b 函数没有被执行,在 a 函数结束的时候把 b 函数返回了出去,在全局 var 一个 demo 等 于 a 执行,就是说现在把 a 函数的返回值赋给了 demo,也就是说 demo 里边现在装的是 b 函数。好,a 函数现在执行完了,他要销毁自己的 AO,我们看着好像就连同 b 函数一块儿被销毁了,然而并没有,全局的 demo 现在就是里边的函数 b,而且手里还攥着 a 的劳动成果,就是说虽然 a 把自己的 AO 销毁了,然而 b 手里还有 a 的 AO 和 GO 呢,而 且还被保存到了外部的 demo 里,所以你在外边执行 demo,就等于执行函数 b,执行时要访问 aaa,先创建自己的 AO 放到作用域链最顶端,然后发现自己的 AO 里没有 aaa, 然后往下找,找到 a 的 AO 有变量 aaa,然后输出得 123,我们视觉上看着好像 b 函数被保存到了外部,再去访问函数里的 aaa 好像是不行的,然而事实上是可以的,这个过程就叫做闭包。
注意:这里把 b 扔给 demo 扔的是引用值,就等于把 b 的地址扔给 demo 了。demo 和 b 就相当于同一个人的不同名字,所以 demo 执行就等于 b 执行。
闭包的产生:但凡内部函数被保存到了外部,它一定生成闭包。例如上边的,内部函数会保存外部函数的劳动成果,然后还没执行呢,就通过 return 的方式被保存到了外部,一保存到外部,那么 a 函数想删除自己的 AO 都删除不了了,因为 b 始终攥着呢。
(2)闭包的应用 :
这里为了方便理解我们再来看一个例子:
function a(){
var num = 100;
function b(){
num ++;
console.log(num);
}
return b;
}
var demo = a();
demo();
demo();
解析:a 执行时产生了自己的 AO 和 GO,然后 b 在定义的时候拿到 a的劳动成
果,a 函数最后把 b 返回给了 demo,然后 a 销毁自己的 AO,然而 demo现在
就是 b 函数,他还保存着 a 的 AO 和 GO,所以 demo第一次执行的时候 b 先
创建自己的AO,然后自己的 AO 里边没有num,就去 a 的 AO 里拿,然后++,输
出得 101,销毁自己的 AO,然后第二次 执行时在创建自己的 AO,没有num,然
后去 a 的 AO 里拿,此时 num是 101,再++,输出得 102,这里每次执行创建
和销毁的是 b 的 AO,然而里边并没有东西,他始终拿的是 a 的 AO 里的num,
a 的 AO 一直存在着。
(3)闭包的现象 :
当内部函数被保存到外部时,就会生成闭包,闭包会导致原有作用域链不释放,造成内存泄露。
解释:例如上边的例 1,本来 a 执行完之后就会销毁自己的 AO,但是 b 被扔出来之后他说你销毁了也是白扯,我还拿着呢!所以他就会导致作用域链该释放的时候不释放,你有意做的闭包还好,假如闭包是无意做的,那就很占内存空间了。所以就会造成内存泄露,什么叫内存泄露?可以这么理解,你占得内存多了,剩余的内存就少了,我们关注剩余的内存,他是不是越来越少?就好像泄露了一样。所以这得反向的理解。
(4)闭包的作用 :
作用一:实现公有变量,比如函数累加器:
function(){
var count = 0;
function demo(){
count ++;
console.log(count);
}
return demo;
}
var counter = add();
counter();
counter();
counter();
解析:我们用闭包就可以做一个函数累加器,在 add 里边先定义一个变量 count,然后定义一个函数 demo,demo 里实现 count++,最后把 demo 扔给全局的 counter,自此之后 counter 就会把 count 无限用了,你每调用一次 counter 他就会在原有的基础上加 一次,这样做就更加模块化,你每执行一次方法他就会累加一次,结构化更好。
作用二:可以做缓存(存储结构)
function test(){
var num = 100;
function a(){
num ++;
console,log(num);
};
function b(){
num --;
console.log(num);
};
return [a,b];
}
var myArr = test();
myArr[0]();
myArr[1]();
解析:首先定义一个 test 函数,test 里边 var 一个 num 等于 100,还放着两个函数 a 和 b,a 函数里边让 num++,b 函数里边让 num- -,然后在 test 最后通过数组的方式把 a 和 b 都扔给外部的 myArr,这也可以形成闭包,你在下边执行 myArr 的第 0 位就等于 a 函数执行,执行 myArr 的第 1 位就等于执行 b 函数,先执行 a 函数,a 拿的是 test 的 AO,num++后输出得 101,再执行 b 函数,b 和 a 同级,拿的也是 test 的 AO,由于刚才 num 被 a++后得 101,所以再 - - 输出得 100.
示例:
function eater(){
var food = ''; //food 初始化
var obj = {
eat : function(){
console.log("im eating" + food)
food = ''; //food 清空
}
push : function(myFood){
food = myFood; //给 food 赋值
}
}
return obj;
}
var eater1 = eater();
eater1.push("banana");
eater.eat();