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

Why variable object was changed to lexical environment in ES5?

本文关键字:词法 环境 对象 变量 ES5 为什么      更新时间:2023-09-26

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

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

Environment Record记录了创建的标识符绑定

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

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

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

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

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

不可变绑定的创建和初始化是不同的步骤这样的绑定可以存在于初始化或uninitialised状态。

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

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

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

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

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

也就是说,规范不要求(甚至间接不建议)将声明性记录实现为简单对象,在这种情况下,这是低效的。这一事实的结果是声明性环境记录不会直接暴露给用户级,这意味着我们不能像访问记录的属性那样访问这些绑定。实际上,我们以前也不能这么做,甚至在ES3中也不能;激活对象也是无法直接访问的用户(除了Rhino实现仍然通过__parent__属性暴露它)。

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

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

因此,正如Brendan Eich也提到的(最后一段)—ES3中的激活对象实现只是“一个bug”: “我要指出的是,ES5中有一些真正的改进,特别是第10章,它现在使用声明式绑定环境。ES1-3’ ’ ’ ’ ’ ’ ’ ’ ” ”

是一个bug,而不是一个特性”。