简单总结一下JavaScript中的闭包的原理。
闭包定义
简单的来说,JavaScript中的闭包可以可以定义为:可以访问外部变量的函数。
那么JavaScript是如何实现这种功能的呢?
词法环境
在JavaScript内部实现中,函数或代码块实际上也是js的Object,本质上也是(key,value)的集合,局部变量的变量名就是Object内的属性名,而变量的值则是对应的属性值。对局部变量的赋值/修改操作实际上就是对于这个Object内的属性的赋值/修改操作。这种Object被称为词法环境(Lexical Environment)。
词法环境这个Object包括两部分:
- 环境记录(Environment Record),也就是作为局部变量来实用的Object属性
- 一个指向外层的词法环境的引用[[Environment]](大括号的外面一层)。当访问了本词法环境中没有的属性名的时候,js会访问这个引用,到更外层的词法环境中去查询属性名,并且这个过程会递归进行,直到查询到最外层为止。
在js中,当一个函数/代码块声明的时候,会把这个函数/代码块对应的[[Environment]]规定为本层的词法环境引用,但此时由于函数/代码块还没有实际执行,所以还没有在内存中真正创建词法环境实体,等到这个函数/代码块实际调用执行的时候,才会真正创建新的词法环境,并把这个词法环境中的[[Environment]]真正设置成之前所规定的引用值
例子
下面是一个简短的代码例子:
1 |
|
妈的,原本想简单地总结一下的,没想到写得这么繁琐这么绕,,,
例外情况
如果使用new Function(…)来创建函数,则不满足上述的规则,new Function创建出来的函数,它们的[[Environment]]指向的是全局的词法环境(即最外层的)