闭包的理解
闭包的定义
维基百科
- 闭包 Closure,又称词法闭包或函数闭包
- 是在支持头等函数的编程语言中,实现词法绑定的一种技术
- 闭包在实现上是一个结构体,它存储了一个函数和一个关联的环境
- 闭包跟函数最大的区别在于 当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样的话,及时脱离捕捉时的上下文,它也能正常运行
MDN
- 闭包是由捆绑起来(封闭的)的函数和函数周围状态(词法环境)的引用组合而成。
- 换言之,闭包让函数能访问它的外部作用域。
- 在 JavaScript 中,闭包会随着函数的创建而同时创建。
个人理解
- 对于一个普通函数,若他能访问外层作用域的自由变量,则这个函数结构就可以称为闭包
- 广义来看,JS 的函数都是闭包,因为在全局中的函数也在访问全局作用域的自由变量
- 狭义来看,一个访问了外部作用域自由变量的函数(组成的结构)就是一个闭包
- 闭包是一种结构
作用域/自由变量域是在编译时,就确定的
我的问题
- 所谓编译时,指的是 parse 在进行词法分析的时候吗?
闭包的最简示例分析
ES1-3

ES 新-结合执行上下文、环境记录分析(纯属个人理解)
代码:
javascript
function foo() {
var age = 18;
return function bar() {
console.log(age);
};
}
var fn = foo();
fn(); // 18分析:
- 在 v8 开始后,引擎会初始化代码执行所需要的环境,比如 ECS、内存、全局对象...
复习:全局对象的创建是在进入任何执行上下文之前
- 创建全局执行上下文&全局环境记录,全局执行上下文中有执行上下文所对应的那些组件,词法环境、变量环境与全局环境记录相关联
- 解析遇到 foo 函数定义,会创建 foo 函数的函数对象,执行到
var fn = foo(),在执行前夕,会创建函数环境记录 & 函数执行上下文

- 开始执行 foo, var age = 18,在 foo 的执行上下文中找到 age 变量,将值改为 18,然后执行到 return,遇到了 bar 函数声明,就会在内存中创建 bar 函数对象 & 创建 bar 函数环境记录,将 bar 函数 return

- return 后 foo 函数执行完成,return bar 函数,foo 执行上下文销毁,此时正常来讲 foo 函数环境记录也应该销毁,但是由于 bar 函数环境记录中的 outerEnv 指向 foo 函数环境记录,所以 foo 函数环境记录未被销毁
- 然后 给 fn 赋值,在全局执行上下文中找到 fn, 赋值为 bar
- fn 执行,创建 bar 函数执行上下文,执行到打印 age,先在自己执行上下文对应的环境记录中寻找,找不到通过 outerEnv 找到 foo 函数环境记录,找到变量 age

闭包的应用场景
函数封装
柯里化
数据私有
内存泄漏 & 防止
内存泄漏防止:
javascript
function foo() {
var age = 18;
return function bar() {
console.log(age);
};
}
var fn = foo();
fn(); // 18
// 防止内存泄漏
fn = null;