6

ES5 将变量对象(VO) 更改为词法环境。既然 VO 作为感知已经非常明显,那么这种变化的动机是什么?

4

2 回答 2

2

我认为变量对象更类似于环境记录

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

在 ES5 中有两种不同的环境记录:

声明性环境记录用于定义 ECMAScript 语言句法元素的效果,例如FunctionDeclarationsVariableDeclarationsCatch子句,它们直接将标识符绑定与 ECMAScript 语言值相关联。对象环境记录用于定义 ECMAScript 元素(例如ProgramWithStatement )的效果,它们将标识符绑定与某些对象的属性相关联。

所以问题是为什么要引入声明性环境记录,而不是像 ES3 变量对象那样仅使用对象环境记录。不同之处在于声明性环境记录可以具有不可变的绑定:

除了所有环境记录支持的可变绑定之外,声明性环境记录还提供不可变绑定。不可变绑定是标识符和值之间的关联一旦建立就不能修改的绑定。

不可变绑定在对象中没有直接等价物。一个属性可以定义为不可配置和不可写,变成不可变的。然而,

不可变绑定的创建和初始化是不同的步骤,因此此类绑定可能以已初始化或未初始化状态存在。

但是你不能有一个未初始化的属性。如果您定义了一个不可配置的不可写属性,其值为 undefined,那么您将无法将其初始化为所需的值。

我认为在 ES5 中不可能有未初始化的不可变绑定。CreateImmutableBinding 仅在声明绑定实例化函数定义中使用,并且在这两种情况下,它都会立即使用 InitializeImmutableBinding 进行初始化。

但这样做可能是为了允许未初始化的不可变绑定作为语言的扩展,例如 JavaScript 1.5 const。或者他们可能已经想到了 ES6 const

于 2016-11-11T20:07:05.600 回答
1

您链接的 ES3 文章的同一位作者也写了关于 ES5 的文章(甚至在那里链接了该部分)。我将在ECMA-262-5 中的“声明性环境记录”部分详细引用 Soshnikov 先生。第 3.2 章。词法环境:ECMAScript 实现

在一般情况下,声明性记录的绑定被假定直接存储在实现的低级别(例如,在虚拟机的寄存器中,从而提供快速访问)。这是与 ES3 中使用的旧激活对象概念的主要区别。

也就是说,规范不需要(甚至间接不推荐)将声明性记录实现为在这种情况下效率低下的简单对象。这一事实的结果是声明性环境记录不假定直接暴露给用户级,这意味着我们不能访问这些绑定,例如记录的属性。实际上,我们以前也做不到,即使在 ES3 中——用户也无法直接访问激活对象(尽管 Rhino 实现仍然通过属性公开了它)。__parent__

潜在地,声明性记录允许使用完整的词法寻址技术,即无需任何范围链查找即可直接访问所需的变量——不管嵌套范围的深度(如果存储是固定的且不可更改的,则可以知道所有变量地址即使在编译时)。然而,ES5 规范并没有直接提到这个事实。

所以再一次,我们应该理解为什么需要用声明性环境记录替换旧的激活对象概念的主要事情是实现的效率

因此,正如 Brendan Eich 也提到的(最后一段)——ES3 中的激活对象实现只是一个“错误”:“我会注意到 ES5 中有一些真正的改进,特别是第 10 章现在使用声明性绑定环境. ES1-3 对范围对象的滥用(我再次责备我在 1995 年在 JS 中这样做,急需实现语言所需的对象)是一个错误,而不是一个特性”

我不认为我可以更好地表达这一点。

于 2016-11-11T23:45:29.000 回答