一,什么是闭包?
在《你不知道的JavaScript》一书中是这样描述的:当函数可以记住并访问所在的作用域时,就产生了闭包,即使函数是在当前作用域之外执行。
二,闭包的用途是什么?
1、读取函数内部的变量。
2、让这些变量的值始终保持在内存中。不会再因为调用后被垃圾回收自动清除。
3、方便调用上下文的局部变量,利于代码封装。
例如:for循环中使用定时器延迟打印的问题
for (var i = 1; i <= 10; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
在这段代码中,我们对其的预期是输出1~10,但却输出10次11。这是因为setTimeout中的匿名函数执行的时候,for循环都已经结束了,for循环结束的条件是i大于10,所以会输出10次11。 原因:i是声明在全局作用中的,定时器中的匿名函数也是执行在全局作用域中,所以每次都输出11。 原因知道了,解决起来就简单了,我们可以让i在每次迭代的时候,都产生一个私有的作用域,在这个私有的作用域中保存当前i的值。
for (var i = 1; i <= 10; i++) {
(function () {
var j = i;
setTimeout(function () {
console.log(j);
}, 1000);
})();
}
这样就达到我们的预期了,让我们用一种比较优雅的写法改造一下,将每次迭代的i作为实参传递给自执行函数,自执行函数中用变量去接收:
for (var i = 1; i <= 10; i++) {
(function (j) {
setTimeout(function () {
console.log(j);
}, 1000);
})(i);
}
三,闭包的缺点是什么?
1,闭包会驻留在内存中,会增大内存使用量,使用不当很容易造成内存泄露,降低程序的性能,但是这并不是闭包本身的错误造成的,而是由于我们自己使用不当。更重要的是,对闭包的使用不当会造成无效内存的产生 解决方法是,在退出函数之前,将不使用的局部变量全部删除。
例子:
function showId() {
var el = document.getElementById("app")
el.onclick = function(){
aler(el.id) // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
}
}
// 改成下面
function showId() {
var el = document.getElementById("app")
var id = el.id
el.onclick = function(){
aler(id) // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
}
el = null // 主动释放el
}
2,闭包会在父函数外部,改变父函数内部变量的值。
举例
function fun(){
var a=12; //这是变量a的值是12.
function fun1(){
return ++a;
}
return fun1;
}
var a=fun();
a();//这个时候变量a的值是13了;
a();//这个时候变量a的值是14了;
a();//这个时候变量a的值是15了;