个人理解的闭包,特此记录下来。
1、封闭内部变量,仅可被该返回函数访问
var counter = function() {
var count = 0;
return function() {
console.log(count++);
}
}
在上述counter函数中,内部的count无法被外部代码访问,除非用counter();
eg:
counter(); // 1
counter(); // 2
counter(); // 3
2、变量长期存于内存中
还是上面这个例子,因为counter()返回的是函数,在js里面函数即对象,相当于counter()返回了一个对象,这个对象在内存中开辟了内存地址,导致它内部的count一直能被访问,所以这个count变量一直没法被释放,故一直存于内存中。如果有时候想要长期管理一个变量,可以使用闭包的方式。但是切记项目中不能有过多的闭包,否则太多变量无法得到释放会造成内存溢出。
闭包核心点:
var x = "outer";
function father() {
var x = "father";
return child;
}
function child() {
return x;
}
father()(); // father
其实就是自由变量的读取,是从函数定义的地方,而不是函数运行的地方。
知道了这一点,之前的一些闭包经典例子应该都能理解。
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, i*1000);
}
// 5
// 5
// 5
// 5
// 5
如上面例子中的i,读取它是从 函数定义的地方,如上所知,这个i所在的函数作用域是在for循环中,也就是全局作用域。
因为执行setTimeout回调的时候,i已经走完循环了,所以会输出5个5。
现在我们来改良一下上诉代码
for(var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function() {
console.log(j);
}, j*1000)
})(i)
}
// 0
// 1
// 2
// 3
// 4
用自执行匿名函数,把i作为实参,j为形参传递给匿名函数。这时候匿名函数中的setTimeout里面的j,读取的是变量在匿名函数定义的地方也就是作为形参的j。此时的j是通过闭包保存在匿名函数内部,所以每1秒执行console.log的时候,能够打印出准备的j值
当然在for循环中用let定义i,也能正确打印i值。
这是因为let能够创造块做作用域。而var不行。我估计let内部应该也是用闭包去实现的。
表达能力有限,暂时只能这么描述了。供以后复盘用吧。