闭包的本质
- js 是词法有作用域语言
- 基于标记清除法的垃圾回收机制
词法作用域(源码作用域)
Dart 和 js 都是词法有作用域语言,变量的作用域在写代码的时候就确定了,大括号内定义的变量只能在大括号内访问
词法闭包
函数能够访问到的变量在它定义(书写)的时候就已经确定了
function makeAdder(addBy) {
return i => addBy + i;
}
(function () {
let add2 = makeAdder(2);
// Create a function that adds 4.
let add4 = makeAdder(4);
// 闭包
console.log(add2(3))
console.log(add4(3))
})()
// 5
// 7
函数 add2 和 add4 在书写的时候是可以访问到变量 addBy 的,而后续函数 add2 和 add4 可能会用到这个变量,因此在函数 makeAdder 执行完成后,变量 addBy 并没有被销毁
以上的特性就是闭包(词法闭包)
很明显,利用闭包可以在内存中维护一个状态变量
基于标记清除法的垃圾回收机制
比如下面的代码:
当退出函数后,局部变量 a 并没有消失,而是似乎一直在某个地方存活着。这是因为当执行var f = func();时,f 返回了一个匿名函数的引用,它可以访问到 func() 被调用时产生的环境,而局部变量 a 一直处在这个环境里。既然局部变量所在的环境还能被外界访问,也就是说基于标记清除法的垃圾回收机制不会回收这个局部变量。在这里产生了一个闭包结构,局部变量的生命看起来被延续了