【问题标题】:Activation Object in JavaScript closuresJavaScript 闭包中的激活对象
【发布时间】:2014-05-05 13:20:59
【问题描述】:

我正在试图弄清楚闭包是如何在 JS 中实现的(理论上),但有一件事让我感到困惑,我找不到答案。

JS 中的闭包使用一个激活对象链。每个函数调用都有一个,它指向其父级的激活对象,后者指向父级的激活对象,依此类推。

如果我理解正确的话,这种情况下的“父”是子函数在其中定义的函数调用。

但是孩子怎么知道它父母的激活对象呢?子函数可以在程序的任何地方调用,甚至在定义它的函数调用之外。定义函数时,父级的激活对象是否以某种方式存储在函数对象本身中?每个函数调用是否以某种方式从其自己的函数对象中获取其父级的激活对象?这是我能想到的唯一解释,但我无法验证。

另外,有没有办法检查激活对象(很像如何检查__proto__)?

【问题讨论】:

    标签: javascript closures


    【解决方案1】:

    至少按照 ECMA 的术语,您所描述的内容被定义为 Lexical Environment

    词法环境由Environment Record对外部词法环境的可能为空的引用组成。

    每个function 都被定义为有一个internal [[Scope]] property(参考:表9),它引用了一个这样的环境。

    Function.[[Scope]] ->
      LexicalEnvironment.Outer ->
        LexicalEnvironment
        # etc.
    

    这里的.Outer属性只是一个猜测,但是引擎引用外部环境,它的值是当前上下文环境的值——周围function[[Scope]]或程序本身。

    当调用 function 并引用变量时,引擎可以遍历环境及其记录的“作用域链”,直到找到被引用的名称或用完环境并抛出一个ReferenceError


    另外,有没有办法检查激活对象(很像如何检查__proto__)?

    目前在语言本身内是不可能的。内部属性不能直接在 JavaScript 中访问,[[Scope]] 属性没有任何东西可以暴露它,就像[[Prototype]] 属性有Object.getPrototypeOf()__proto__

    但是,正如 Bergi 所说,JavaScript 调试器可能允许您检查作用域链。例如under "Scope Variables" in Chrome's Web Tools:


    (来源:google.com

    脚本暂停时,您可以在右侧栏中看到当前调用堆栈和范围内的变量。

    【讨论】:

    • Chrome 控制台显示闭包的作用域对象,您也可以随时检查每个调试器中的作用域链。
    猜你喜欢
    • 2011-09-14
    • 2012-07-23
    • 1970-01-01
    • 2018-11-20
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2018-07-07
    相关资源
    最近更新 更多