什么是闭包?
在JavaScript中,闭包(closure)是指函数与其词法环境的组合。它允许函数在其定义的词法作用域之外访问变量,并保持对这些变量的引用,即使在函数外部被调用时仍然有效。
闭包由两个主要部分组成:
函数:闭包是一个函数,它定义了一些变量和逻辑。
词法环境:词法环境是在函数定义时创建的作用域,它包含了函数中定义的变量和它们的值。
从广义上来说,任何JavaScript函数都是闭包,比如在浏览器中,任何一个函数都有一个global对象,那就是window,而在node环境中,每个函数也有一个global对象。
从狭义上来说,JavaScript中一个函数,如果访问了外层作用域的变量,那么它是一个闭包。
通俗易懂地讲,一个普通的函数function,如果它可以访问外层作用于的自由变量,那么这个函数就是一个闭包。
闭包的形成过程
现在有如下代码。
function makeAdder(base) {
return function (num) {
return base + num;
}
}
const add10 = makeAdder(10)
console.log(add10(5)); // 15
当makeAdder函数执行完毕,正常情况下我们的Activation Object(AO)对象会被释放;但是在返回的函数中,有作用域引用了这个AO对象的base,所以它不会被释放。
Activation Object是什么?
当一个函数执行的时候,会创建一个Activation Object。该对象会存储该函数体内的变量以及arguments等信息。
闭包的内存泄露
在上面的案例中,如果后续我们不再使用add10函数了,那么该函数对象应该要被销毁掉,并且其引用着的父作用域AO也应该被销毁掉;但是目前因为在全局作用域下add10变量对makeAdder执行后的函数对象(AO)有引用,所以最终会造成这些内存都是无法被释放的;
所以我们经常说的闭包会造成内存泄露,其实就是刚才的引用链中的所有对象都是无法释放的;
解决内存泄露
add10 = null
//根据GC机制,将add10引用赋值为null,就不会有引用指向makeAdder创建出来的函数对象,从而也会将其销毁
闭包中未使用外层的属性是否被销毁?
function makeAdder(base) {
const msg = "hello"
return function (num) {
return base + num;
}
}
这段代码中,base和msg都属于父级作用域中的AO,base不会被销毁,但msg会被销毁
作者:CoderYoo
链接:https://leetcode.cn/problems/create-hello-world-function/solutions/2272042/ni-bu-zhi-dao-de-bi-bao-by-coderyoo-w3rl/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。