闭包是由函数以及声明该函数的词法环境组合而成的
- 一种常见的闭包问题
var t = [];
function getColor(color) {
console.log(color);
}
function test() {
var colors = ["red", "white", "black"];
for (var i = 0; i < colors.length; i++) {
var nowColor = colors[i];
// 这里给t[i]赋值采用的是闭包的形式,nowColor使用了var的方式进行声明,故存在变量提升,
// 所以具有函数作用域。再t[i]中的事件进行调用的时候,循环早已结束,
// 故对应的color都指向了colors的最后一项
// 简单的解决方法就是将nowColor使用let方式声明
t[i] = function () {
getColor(nowColor);
};
}
}
test();
t.forEach((x) => {
x(); // 控制台输出了三次black,而不是依次输出red,white, black
});
- 在函数体内声明的变量就是一个天然的闭包。
var p = 'x'
var func = function() {
var x = 'tj'; //闭包中声明的变量(局部变量)在退出函数后会被销毁
console.log(x); // 'tj'
console.log(p); // 'x'
}
console.log(x) // x is not defined
func() // 'tj'
- 函数体外不能访问到函数体内声明的变量,不过函数体内可以拿到函数体外声明的变量。 函数a中声明的变量如果被函数体内的函数引用了,那么在函数a中声明的变量就不一定会随着函数的退出而被销毁。
var a = function() {
var x = 1;
return function() {
x++;
console.log(x);
}
}
var f = a();
//可见x的值一直被保存在了内存里,因为x一直被a函数体内的匿名函数所应用
f(); //2
f(); //3
- 闭包还可以用来延续局部变量的寿命
// 局部变量n用闭包的方式封闭起来
let numbers = (function() {
let cache = [];
return function(num) {
let n = {value: num}
cache.push(n);
console.log(cache);
}
})()
numbers(1) // [{value: 1}]
numbers(2) // [{value: 1},{value: 2}]
在闭包的使用时,常常要和内存管理一起联系起来。是的,在使用闭包的时候,我们会主动把一些变量封装在闭包中,这些变量是在之后的使用中可能再次用到的,它们存放在闭包或者全局变量中,对内存的影响是差不多的。不过在我们确认这些变量不需要时,可以手动将这些变量设置为null。当然,闭包的使用中,一定要避免循环引用,这样能有效的避免内存泄露。