我试图弄清楚JS中的闭包是如何实现的(理论上),有一件事让我困惑,我无法找到答案。
JS中的闭包使用一系列激活对象。每个函数调用都有一个,它指向其父对象的激活对象,该对象指向其父对象的激活对象,依此类推。
如果我理解正确的话,"父母"在这种情况下是函数调用,其中子函数是定义的。
但孩子如何知道其父母的激活对象?子函数可以在程序中的任何地方调用,甚至可以在定义它的函数调用之外调用。在定义函数时,父对象的激活对象是以某种方式存储在函数对象本身中的吗?每个函数调用是否以某种方式从其自己的函数对象获取其父对象的激活对象?这是我能想到的唯一解释,但我无法验证。
另外,有没有办法检查激活对象(很像是如何检查__proto__
)?
答案 0 :(得分:1)
至少根据ECMA的条款,您所描述的内容被定义为Lexical Environment。
词汇环境包含Environment Record和对外部词汇环境的可能为空的引用。
每个function
被定义为internal [[Scope]]
property(参见表9),它引用了一个这样的环境。
Function.[[Scope]] ->
LexicalEnvironment.Outer ->
LexicalEnvironment
# etc.
这里的.Outer
属性只是猜测,但引擎引用外部环境,其值是当前上下文环境的值 - 周围{{1}的[[Scope]]
或程序本身。
当调用function
并引用变量时,引擎可以遍历环境及其记录的“范围链”,直到找到引用的名称或用完为止环境和投掷function
。
另外,有没有办法检查激活对象(很像是如何检查
ReferenceError
)?
目前在语言本身内是不可能的。无法在JavaScript中直接访问内部属性,__proto__
属性没有任何内容可以公开[[Scope]]
属性[[Prototype]]
或Object.getPrototypeOf()
。
但是,正如Bergi所提到的,JavaScript调试器可能允许您检查范围链。例如,under "Scope Variables" in Chrome's Web Tools:
当脚本暂停时,您可以在右侧栏中看到当前的调用堆栈和范围内变量。