前言
本文专门介绍闭包,但事实上,闭包的难点并不在概念,而是在词法环境的嵌套上。只要将词法环境的嵌套关系整理清楚,闭包就瞬间被克服了。
总之,先不废话了,正文开始。
闭包
如果一个函数在定义的词法环境外运行并记住了定义时的词法环境,这样的现象就可以称作函数闭包(Function Closure)
举个简单例子:
function f(x=0){
var count=x;
function getCount(){
return count++;
}
return getCount
}
var func = f(10);
console.log(func()); // 10
console.log(func()); // 11
console.log(func()); // 12
console.log(func()); // 13
console.log(func()); // 14
首先要明白上面代码究竟发生了什么,梳理一下过程:
函数f
返回了函数getCount
的引用, 并将局部变量count设为了10
。- 外部词法环境中,
func
指向了getCount
然后在执行func
时就很神奇的进行了叠加。
为了直观表示,我就是用图示法表示环境绑定了(也可以用执行上下文伪代码):
注意: func
和getCount
没有在同一个词法环境。
那么执行过程就是:
func
引用自getCount
所指向的函数。- 调用
func
会进入getCount
的词法环境 - 解析标识符
count
,在当前词法环境中未找到,进入外部词法环境; - 在外部词法环境找到,返回值后叠加。 --> 保存词法环境状态
- 再次调用
func
时,会再次访问外部词法环境,访问count
,此时count
为11,然后返回。 - ……
可以注意到:形成函数的闭包的关键在于:它会保存外部词法环境的状态。
但是为什么会这样?
闭包实现 I: 执行上下文也会创建外部环境
- 函数调用时,会为该函数创建一个执行上下文。
- 执行上下文中会创建当前词法环境的环境记录,记作
CurrentEnvRec
- 除了会创建
CurrentEnvRec
,还会创建外部词法环境的环境记录, 记作OuterEnvRec
- 如果
OuterEnvRec
还有