为什么在 ES5 中变量对象被改为词法环境?

Why variable object was changed to lexical environment in ES5?

ES5 将 variable object(VO) 更改为词法环境。 VO作为感知已经很明显了,这样改变的动机是什么?

我认为可变对象更类似于environment records

An Environment Record records the identifier bindings that are created within the scope of its associated Lexical Environment.

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

Declarative environment records are used to define the effect of ECMAScript language syntactic elements such as FunctionDeclarations, VariableDeclarations, and Catch clauses that directly associate identifier bindings with ECMAScript language values. Object environment records are used to define the effect of ECMAScript elements such as Program and WithStatement that associate identifier bindings with the properties of some object.

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

In addition to the mutable bindings supported by all Environment Records, declarative environment records also provide for immutable bindings. An immutable binding is one where the association between an identifier and a value may not be modified once it has been established.

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

Creation and initialisation of immutable binding are distinct steps so it is possible for such bindings to exist in either an initialised or uninitialised state.

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

我认为在 ES5 中不可能有未初始化的不可变绑定。 CreateImmutableBinding 仅在 Declaration Binding Instantiation and Function Definition 中使用,并且在这两种情况下都会立即使用 InitializeImmutableBinding 进行初始化。

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

您链接的 ES3 文章的同一作者也写了关于 ES5 的文章(甚至在那里链接了该部分)。我会引用 Soshnikov 先生的 "Declarative environment record" section in ECMA-262-5 in detail. Chapter 3.2. Lexical environments: ECMAScript implementation:

In general case the bindings of declarative records are assumed to be stored directly at low level of the implementation (for example, in registers of a virtual machine, thus providing fast access). This is the main difference from the old activation object concept used in ES3.

That is, the specification doesn’t require (and even indirectly doesn’t recommend) to implement declarative records as simple objects which are inefficient in this case. The consequence from this fact is that declarative environment records are not assumed to be exposed directly to the user-level, which means we cannot access these bindings as e.g. properties of the record. Actually, we couldn’t also before, even in ES3 — there activation object also was inaccessible directly to a user (except though Rhino implementation which nevertheless exposed it via __parent__ property).

Potentially, declarative records allow to use complete lexical addressing technique, that is to get the direct access to needed variables without any scope chain lookup — regardless the depth of the nested scope (if the storage is fixed and unchangeable, all variable addresses can be known even at compile time). However, ES5 spec doesn’t mention this fact directly.

So once again, the main thing which we should understand why it was needed to replace old activation object concept with the declarative environment record is first of all the efficiency of the implementation.

Thus, as Brendan Eich also mentioned (the last paragraph) — the activation object implementation in ES3 was just “a bug”: “I will note that there are some real improvements in ES5, in particular to Chapter 10 which now uses declarative binding environments. ES1-3’s abuse of objects for scopes (again I’m to blame for doing so in JS in 1995, economizing on objects needed to implement the language in a big hurry) was a bug, not a feature”.

我认为我无法更好地表达这一点。