一、闭包的定义
我们先看一段代码:
function foo() {
var name = "foo"
function bar() {
console.log("bar", name)
}
return bar
}
var fn = foo()
fn()
我对闭包的理解:
一个普通的函数(bar),如果它可以访问外层作用域的自由变量(name),那么这个函数就是一个闭包
广义的角度:
JavaScript中的函数都是闭包
狭义的角度:
JavaScript中一个函数,如果访问了外层的变量(上层作用域的变量),那么它是一个闭包;否则,它不是一个闭包
比如test1访问了外层的自由变量(name),那么test1函数是一个闭包;但是,test2没有访问外层的自由变量,所以test2不是一个闭包。
var name = "kk"
// 这个函数访问了外层作用域的变量
function test1() {
console.log(name)
}
// 这个函数没有访问外层作用域的自由变量
function test2() {
console.log('test2函数没有访问外层作用域的变量');
}
二、闭包的内存泄漏
先看下面的闭包:
function foo() {
var name = 'zyk'
var age = 20
function bar() {
console.log(name);
console.log(age);
}
return bar;
}
var fn = foo()
fn()
下面是上面代码的执行过程:
解析:(根据GC算法-标记清除)原本当每个函数执行上下文栈执行完后,它对应的AO对象都会被销毁,但是,这里的GO对象的属性fn指向bar函数的内存地址,然后bar函数的内存地址又指向foo函数的AO对象,只要GO对象一直指向,那么AO对象永远都不会都不会被销毁。 这就是闭包的内存泄漏
销毁内存泄漏:
如果后续我们不再使用fn函数了,那么该函数对象应该要被销毁掉,并且其引用着的父作用 域AO也应该被销毁掉; 但现在fn引用了bar函数对象,所以不能被销毁。如果将fn = null,则可以解决内存泄漏,当设为null,则fn只会指向一个空的地址,bar的函数对象则没有给引用,则会给销毁,AO也会被销毁掉。