一 什么是闭包
闭包是由捆绑起来(封闭的)的函数和函数周围状态(词法环境)的引用组合而成。
可以把闭包看作是在函数环境中,一个函数(必须引用外部数据)与其周围状态(词法环境)的组合。
也就是说,闭包包含两个部分,一是执行环境A,二是在A中的函数B,闭包通过B的调用而被激活使用。
举个例子:在makeFunc函数中,displayName函数形成了闭包,return出的displayName函数,实际是一个闭包,它包含了整个执行环境,所以能在后面的调用中访问到执行环境中的name属性。
function makeFunc() {
const name = "Mozilla";
function displayName() {
console.log(name);
}
return displayName;
}
const myFunc = makeFunc();
myFunc();
二 闭包在js中的独特性
闭包(Closure)是许多编程语言中常见的特性,不同语言对闭包的支持和实现方式有所不同。
相比于其它编程语言,js中的闭包更加灵活,它可以捕获并保留其词法作用域中的变量,并允许修改。
这种灵活性也导致了js的闭包可能会有内存泄漏的风险。
三 关于闭包的内存泄露问题
所谓内存泄漏,即程序动态分配内存后,未通过相应方法进行释放,泄露的内存无法被程序或操作系统回收,导致可用内存持续减少。
js在使用闭包时,有两种情况会导致内存的泄露。
-
持有本该被销毁的函数,造成其关联的词法环境无法被销毁,比如事件监听结束后移除事件监听,但绑定的事件函数还存在于内存之中。
-
当有多个函数共享词法环境时,可能导致词法环境膨胀,从而发生无法访问但无法销毁的数据,比如由于c、d共享词法环境,在调用a后,无法访问函数c,但也无法销毁它。
function a(){
let b = 0;
function c(){
console.log(b);
}
function d(){
console.log(b++);
}
return d;
}
let d = a();
总结:闭包不是在javascript中特有的,但于其它语言中的闭包相比,javascript的闭包更灵活,且有内存泄露的风险。