认识闭包
什么是闭包,简单的说就是函数套函数,内部函数如果能访问到外部函数中声明的私有变量、参数或者其他内部函数,在外部函数的外部调用这个内部函数,这就是闭包,一个动态概念。
最简单的例子:
非闭包:function f(x){
var a=x;
var b=a;
a++;
return b;
}
var c=f(5);
alert(c());
结果为5
闭包:function f(x){
var a=x;
var b=function(){
return a;
}
a++;
return b;
}
var c=f(5);
alert(c());
结果为6
这两段带码的区别就在于红色部分,在蓝色部分彻底展现出来,闭包函数在执行return的时候执行了
function(){
return a;
},结果发现a已经a++了,(狗子!你变了,不过爸爸还是原谅你),就酱,b的值也随着a的变化而更新。
非闭包函数直接把a赋值给b,也就是说把b的值已经写死了,直接return写死的值,GOODGAME。。。
所以,一分长一分强啊兄得。。。还不好好锻炼锻炼。
闭包是函数运行期中的一个动态环境,与函数的静态性截然不同(想象不来,反正书上就这么说的)
总结一句话:闭包的作用就是防止激活对象被正常的销毁。(怎么理解呢,var b=function(){
return a;
}这个闭包体造就了b和a之间的联系,在非闭包函数中如果直接var b=a;则赋值完成后b和a之间再就没啥联系了,从此分道扬镳,前面一只大雁飞啊飞,后面一只大雁追啊追,追上之后咔咔一顿锤,锤完之后谁也不认识谁。。。言归正传,在闭包体中,因为是一个函数嘛,只要我不使用这个闭包体函数,b和a之间那种潜在的联系一直会存在,直到var b=function(){
return a;
}这一部分被执行,所以a在外边随便混,b对a的动态变化一直保持关注。闭包不要过多使用,多占内存)
下面拿书上的一个例子来说
function f(x){
var a=[];//新建一个临时数组
for(var i=0;i<x.length;i++){
var temp=x[i];
// 临时存储每个数组元素
a.push(
// 在数组中添加下面函数返回值
function(m,n){
// 给匿名函数传递参数
return function(){
// 返回另一个匿名函数
alert(m+' '+x[n])
// 弹出一个参数m(静态的)和x数组中的一个数组元素x[n](动态的)【这就是关键点,等下对比说明一下精妙之处在哪里】
}
}(temp,i)
// 将参数temp和i传递给函数,形成了一个闭包体
);
// 随着for循环i的递增,数组中的值以闭包体函数的形式被重新存储在a数组中
}
return a;
}
(function e(){
var a=f(['a','b','c']);
// 调用闭包函数
for(var i=0;i<a.length;i++){
// 循环执行闭包体
a[i]();
}
})();
这个闭包函数实现了动态存储变量所有变化的值。
下面讲一下这个闭包函数的错误写法(我就这么想的,然而。。。。。。it's wrong)
<script>
//现在我们分析一下这个闭包函数到底错在哪儿
function f(x){
var a=[];//新建一个临时数组
for(i=0;i<x.length;i++){
//把数组里的元素循环赋值给temp
var temp=x[i];
a.push(
function(){
alert(temp+' '+x[i]);
}//问题就出在这里,理想情况:当i为0的时候,闭包里的temp和x[i]为a
// 当i为2的时候闭包里的temp和x[i]为b,i为3也如此,按道理来说闭包不就是这么用的嘛,其实思路是对的,只是有一个问题,闭包体会把参数动态更新最新的值,也就是说只要闭包函数一经激活,闭包体就开始干活了,它会把temp更新到最新值,把i更新到最新值,你的第一圈for循环开始的时候,temp已经是c,i已经是3了(i=3时不执行循环体而已,但i已经更新到3了),所以第一圈循环与第二第三圈循环在执行相同的操作,x[3]也就是数组第四个元素未定义的,于是报错,这种感觉就像是杀猪(村里来的不要介意),当听说有猪要杀(闭包函数要执行),不管猪来没来(函数执行没执行),先磨刀(更新变量)嘛,磨刀石上(闭包体上)磨啊磨(动态更新啊更新),当猪来的时候,迎接它的是最快的刀和最温暖的双手,一库~。
);
}
return a;
}
(function e(){
//执行函数e,把
var a=f(['a','b','c']);//执行闭包函数
for(var i=0;i<a.length;i++){
//循环读取闭包体并立即执行
a[i]();
}
})();
</script>