什么是声明性环境记录,它与激活对象有何不同?

Kub*_*oda 13 javascript ecmascript-5

好的,所以我最近一直在阅读ES-5词汇环境范围,我不确定我是否真的理解变量在EcmaScript中的存储方式.我做了一些研究,但没有澄清我的信息,只给我带来了两个问题.所以它们是:

  1. 第一个是关于ES-3 activations objects/ variable objects.在阅读了ES-3规范和Internet上的一些资源后,我可以假设它们只是普通的对象,例如像那些创建的那样new Object,但没有一个消息来源直接说"是的,这只是一个简单的对象".此外,Dmitry Soshnikov在他的博客上写道(重点是我的):

    在示意性和示例中,可以将变量对象呈现为普通的ECMAScript对象

    而且引用并不能让我确定激活对象到底是什么.所以这是第一个问题:激活对象是一个常规的EcmaScript对象吗?如果没有,那么它又是什么呢?

  2. 在我们现在的ES-5中object environment records,它似乎与ES-3激活对象或多或少相同,并且declarative environment records在函数和try-catch语句中替换了激活对象.因此,假设对象环境记录只是普通的EcmaScript对象,那么什么是声明环境记录?规范并没有澄清这一点,而且,从我在那里读到的,我无法想象这不是作为一个对象实现的.因此,如果声明性环境记录不是ES对象,那么它们是什么以及它们在代码执行期间如何实现和表示?

非常感谢您提前为我提供这个主题.

编辑:我想我需要澄清这个问题是什么.我想知道的主要事情是激活对象/对象环境记录和声明性环境记录之间的确切区别.这是我最感兴趣的.

Fel*_*ing 21

首先,您必须意识到所有这些术语都只是描述概念.他们没有规定任何形式的实施.但是因为这很难想象/可视化,将这些概念视为你所知道的事物的实例化会很有帮助,比如地图或表格.

声明性环境记录(DER)和对象环境记录(OER)有一个共同点:它们都是环境记录(ER),在规范中定义为:

环境记录记录在其关联的词汇环境范围内创建的标识符绑定.

这基本上意味着ER跟踪变量和函数名称及其相关值.

考虑这个例子:

var foo = 42;
function bar() { };
Run Code Online (Sandbox Code Playgroud)

相应的ER将有两个条目,一个用于foo,一个用于bar.如果你想象一个ER成为一个表,那么它看起来就像

  name        value
----------------------
  foo          42
  bar    <function object>
Run Code Online (Sandbox Code Playgroud)

现在谈谈DER和OER之间的区别.DER可能是最容易理解的.

声明性环境记录

声明这个术语应该听起来很熟悉,因为我们经常谈论变量声明函数声明.规范说:

每个声明性环境记录与包含变量和/或函数声明的ECMAScript程序范围相关联.声明性环境记录绑定由其范围内包含的声明定义的标识符集.

所以,当你看到

var foo = 42;
Run Code Online (Sandbox Code Playgroud)

要么

function bar() {

}
Run Code Online (Sandbox Code Playgroud)

那么你可以假设他们的名字和值存储在DER中.

对象环境记录

OER不太常见,但在每个JS应用程序中至少存在一个OER.规范将其描述为

每个对象环境记录与称为其绑定对象的对象相关联.对象环境记录绑定直接对应于其绑定对象的属性名称的标识符名称集.

你有没有想过为什么window对象的属性是全局变量?这是因为全局范围的ER是OER:window绑定对象,并且对于每个属性,在OER中创建相应的条目.这也在规范中:

全局环境的Environment Record是一个对象环境记录,其绑定对象是全局对象.

这是一个例子:让我们假设绑定对象是

var obj = {
   answer: 42
};
Run Code Online (Sandbox Code Playgroud)

那么OER就是

    name        value
------------------------
    answer       42
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,绑定object(obj)实际上是一个JavaScript对象.当您使用该with语句时,您处于相同的情况:

var obj = { foo: 42; };

with (obj) {
    foo = foo / 2;
}

console.log(obj);
Run Code Online (Sandbox Code Playgroud)

with创建一个OER并使用传递的对象中的属性名称和值填充它.这就是为什么你可以访问它们而不通过它们明确地引用它们obj.*.如果将一个绑定对象分配给其中一个标识符,则OER还确保使用新值更新绑定对象.


激活对象

它看起来像在ES3中,激活对象(AO)在执行函数时自动创建并且它持有对特殊arguments对象的引用.这似乎与DER有关,但仍然是独立的.
在ES5中,AO的概念似乎不再存在,我认为它是不必要的,因为arguments可以直接添加到执行上下文的DER中.

执行上下文

每当执行一个函数时,都会建立一个新的执行上下文(EC),用于跟踪执行的状态:

执行上下文包含跟踪其关联代码的执行进度所需的任何状态.

这意味着引擎可以添加跟踪执行进度所需的任何信息.但规范还定义了EC 必须具有的组件,其中一个是VariableEnvironment,它是一个ER(可能总是DER,但我不确定).这意味着ER是EC 的一部分.

  • 很好的答案,我非常感谢您的努力。因此,这意味着DER和OER之间的主要(也是唯一)区别是OER始终附有一个纯JS对象,这是它的“绑定对象”? (2认同)
  • 我是这样理解的。还有一些事情仍然令人困惑,例如全局范围内的变量声明是否也存储在 OER 中?可能是因为它们成为全局对象的属性。但我还没有找到一个明确的答案,我不想让它变得更加混乱。 (2认同)