@greenfavo
2015-12-15T21:25:20.000000Z
字数 1463
阅读 694
博客
官方定义:函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中成为“闭包”。即函数定义时的作用域链到函数执行时依然有效。通俗地理解闭包就是指有权访问另一个函数作用域中的变量的函数。创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。
在循环中输出索引常常会遇到这种bug。
var data=[];
for(var k=0;k<3;k++){
data[k]=function(){
console.log(k);
}
}
data[0]();//3
data[1]();//3
上面的例子返回的结果总是i的最后一个值,不是我们期望的和数组下标相对应的i的值。这是因为同一个上下文中创建的闭包是共用一个[[Scope]]属性的。因此上层上下文中的变量“k”是可以很容易就被改变的。这样一来,在函数激活的时候,最终使用到的k就已经变成了3了。如下所示,创建一个闭包就可以解决这个问题了:
//正确写法1
var data=[];
for(var k=0;k<3;k++){
(function(i){//i是形参
data[i]=function(){
console.log(i);
}
})(k)//k是实参
}
data[0]();//0
data[1]();//1
//正确写法2
var data=[];
for(var k=0;k<3;k++){
data[k]=(function(i){
return function(){
console.log(i);
}
}(k));// 传入"k"值
}
data[0]();//0
data[1]();//1
//正确写法3
//这种写法data[k]就立即执行了
var data=[];
for(var k=0;k<3;k++){
data[k]=function(i){
console.log(i);
}(k)
}
将循环索引作为参数传入函数表达式中就可以保存这个局部变量,到调用函数时还可以使用。
function aaa() {
var a = 1;
return function(){
console.log(a++)
};
}
var fun = aaa();
fun();// 1 执行后 a++,,然后a还在~
fun();// 2
aaa = null;//a被回收!!
闭包会使变量始终保存在内存中,如果不当使用会增大内存消耗。所以使用完后将它设为null就会回收了。
函数定义时的作用域链到函数执行时依然有效。
function a(){
var x=1;
return function(){
x+=1;
console.log(x);
}
}
var b=a();
b();//2
b();//3
function func(x,y){
x=x||1;
y=y||2;
var aaa=function(){
console.log(x+y);
};
var sss=function(){
console.log(x-y);
};
return{
add:aaa,
sub:sss
};
}
var a=func();
a.add();//3
a.sub();//-1
a.aaa();//报错
1.希望一个变量长期驻扎在内存中
2.避免全局变量的污染
3.私有成员的存在
闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。主要应用闭包场合主要是为了:设计私有的方法和变量。一般函数执行完毕后,局部活动对象就被销毁,内存中仅仅保存全局作用域。但闭包的情况不同!