我很抱歉又要问一个闭包问题,但我想澄清一下我对JavaScript中闭包实现方式的理解。
考虑以下代码:
考虑以下代码:
01 'use strict';
02 function foo() {}
03 foo();
我在今年早些时候的一个问题中已经确定,这里概念上(如果不是由于引擎优化而实际上)创建了一个闭包。
直到第3行调用foo
时,才会创建相应的执行上下文。
因此,据我所知,根据规范评估此代码时:
- 每个执行上下文都有一个“词法环境”组件,用于解析其中的代码所做的标识符引用(8.3,表23)。
- 调用
FunctionCreate
,并传递对当前执行上下文的“词法环境”组件的引用(称为“作用域”)(14.1.19)。 FunctionCreate
调用FunctionInitialize
,并传递“scope”(9.2.5)FunctionInitialize
确保正在创建的函数对象的 [Environment] 内部插槽设置为“scope”的值(指向当前执行上下文的“词法环境”组件的引用)(9.2.4)
最后,当实际调用 foo
时,我发现规范更难以解释。
- 在
PrepareForOrdinaryCall
中,调用的新执行上下文的 "词法环境" 被设置为调用NewFunctionEnvironment
(9.2.1.1) 的结果。 NewFunctionEnvironment
将对外部执行上下文的 "词法环境" 组件(函数对象的 [[Environment]] 插槽)的引用复制到正在构建的执行上下文的 "词法环境" 组件的EnvironmentRecord
中作为 "外部词法环境引用" (8.1.2.4)。
因此,闭包是以两个步骤实现的:
- 在函数对象实例化时,会创建一个函数对象和封闭执行上下文的"词法环境"之间的链接。这是函数对象的[[Environment]]内部插槽。
- 当调用函数时,对外部执行上下文的封闭"词法环境"组件的引用(函数对象的[[Environment]]插槽的内容)会被复制到新执行上下文的"词法环境"组件的规范-不精确定义(?)/
EnvironmentRecord
(?)子组件中。
这样说是否准确?
let
、const
和class
时,它们不会成为全局对象的属性。因此,是的,每个函数都会关闭全局环境。 - Felix Kling