闭包:指有权访问另一个函数作用域中变量的函数。
function parentFunc(){
var a = 1;
function childFunc(){
console.log(a);
}
return childFunc();
}
闭包的特征:
<1>函数内再嵌套函数;
<2>内部函数可以调用外部函数的参数和变量;
<3>参数和变量不会被垃圾回收机制回收。
闭包的好处:能够实现封装和缓存。使用闭包主要是为了封装对象的私有属性和私有方法,闭包可以避免全局变量的污染。
闭包的缺点:闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄漏。
闭包经典问题:
function parentFunc(){
var arr = [];
for(var i = 0;i<5;i++){
arr[i] = function (){
return i;
}
}
return arr;
}
console.log(parentFunc()[0]()); //5
console.log(parentFunc()[1]()); //5
这里就展现出了几个关键信息,首先分析一下代码:循环中创建了一个匿名函数并将其赋值给arr数组中对应索引的元素,匿名函数作用是返回i值。此时,arr数组中存放的是匿名函数,而匿名函数还没有执行。当调用parentFunc()函数时返回arr数组,再单独执行数组中的元素保存的匿名函数,此时循环已经执行完,所以i值为5。接下来再去调用其它数组元素中的匿名函数也样会获得数值5。
要解决这个闭包所产生的问题,有两种办法:
<1>立即执行匿名函数
function parentFunc(){
var arr = [];
for(var i = 0;i<5;i++){
arr[i] = (function (){
return i;
})();
}
return arr;
}
console.log(parentFunc()); //[0,1,2,3,4]
<2>使用let关键字声明变量:使用let声明变量会形成块级作用域
function parentFunc(){
var arr = [];
for(let i = 0;i<5;i++){
arr[i] = function (){
return i;
};
}
return arr;
}
console.log(parentFunc()[0]()); //0