JavaScript中的闭包,无非就是变量解析的过程。
闭包的相关定义
1.什么是闭包
闭包是值能够读取其他函数内部变量的函数。也就是连接函数内部和函数外部的桥梁。
2.闭包有什么用处
①.读取函数变量
②.让这些变量的值始终存在内存中。由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,因此要慎重使用。
3.闭包的创建
因此创建闭包的常见方式就是在一个函数内部创建另一个函数。
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取它的内部变量,其中f2就是闭包,闭包就是能够读取其他函数内部变量的函数
function f1(){
var n=999;
nAdd=function(){n+=1};
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
这段代码中另一个值得注意的地方,就是”nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
闭包与变量
闭包只能取得包含函数中任意变量的最后一个值,因为闭包所保存的是整个变量的对象,而不是某个特殊的变量。
例子
function box(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(){ //匿名函数里面没有i这个变量,所以会从父级的函数中去找,当找到i时,由于闭包的原因,外层循环完毕之后才返回i,因此匿名函数内部输出的都是10
return i;
};
}
return result;
}
console.log(box()[0]()); //结果:10
可以通过创建另一个匿名函数强制让闭包的行为符合预期:
function box(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = (function(num){
return function(){
return num;
};
})(i);
}
return result;
}
console.log(box()[0]()); //结果:0
上述代码,没有直接将闭包赋给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋给数组。
在调用每个匿名函数时,我们传入了变量i,由于函数参数是按值传递的,所以会将变量i的当前值复制给参数num。
而在这个匿名函数内部,又创建并返回一个访问num的闭包。
这样一来,result数组中的每个函数都有自己num变量的一个副本,因此可以返回各自不同的数值。
ES6中,用let声明块级变量,所以上述代码可以更新为
function box(){
var result = new Array();
for(let i=0;i<10;i++){
result[i] = function(){
return i;
};
}
return result;
}
console.log(box()[0]()); //结果:0