接上篇文章[系列]从ECMAScript Specification中学习执行上下文之Environment Records(中) ,本篇继续介绍Object Environment Record和Global Environment Record
Object Environment Record
Object Environment Record的最核心特点在于其拥有一个绑定对象(binding object),object env绑定了该对象上的所有字符串属性作为env中的标识符,从而可以在相应的scope中直接使用这些标识符,非字符串的属性不会被绑定为标识符。
- 绑定对象本身和继承的属性均会被env绑定为标识符
- 绑定对象属性的增减也会导致env的标识符绑定的变化,所有通过新增绑定对象属性所导致的均为可变绑定(即使该属性是不可写的)
object env有以下几个专有的字段:
| 字段名称 | 可选值 | 释义 |
|---|---|---|
| [[BindingObject]] | 对象 | 即上文中提到的binding object |
| [[IsWithEnvironment]] | 布尔 | 用于表示该env是不是为with语句所创建的 |
Object Environment Record方法的执行逻辑
HasBinding ( N )
- let: bindingObject = env.[[BindingObject]]
- let: foundBinding = HasProperty(bindingObject, N)
- if: foundBinding 为 false,
returnfalse. - if: envRec.[[IsWithEnvironment]] is false,
returntrue - let: unscopables = Get(bindingObject, @@unscopables)
- if: Type(unscopables) 为 Object, 则:
- let: blocked = ToBoolean(? Get(unscopables, N))
- if: blocked 为 true,
returnfalse
returntrue
Get()方法可以简单理解为获取对象的某个属性值,具体可以参考:tc39.es/ecma262/#se…
@@unscopables是一个内置的Symbol,具体可以参考developer.mozilla.org/zh-CN/docs/…
CreateMutableBinding ( N, D )
- let: bindingObject = env.[[BindingObject]]
returnDefinePropertyOrThrow(bindingObject, N, PropertyDescriptor { [[Value]]: undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D }).
DefinePropertyOrThrow可以粗略理解为Object.defineProperty方法,具体可以参考:tc39.es/ecma262/#se…
CreateImmutableBinding ( N, S )
在object env中不会被使用
InitializeBinding ( N, V )
- 直接调用 env.SetMutableBinding(N, V, false)
SetMutableBinding ( N, V, S )
- let: bindingObject = env.[[BindingObject]]
- let: stillExists = HasProperty(bindingObject, N)
- if: stillExists 为 false,并且 S 为 true, 直接抛出 ReferenceError
returnSet(bindingObject, N, V, S)
Set可以粗略理解为一个对象写入属性,具体描述可参考标准:tc39.es/ecma262/#se…
GetBindingValue ( N, S )
- let: bindingObject = env.[[BindingObject]]
- let: value = HasProperty(bindingObject, N)
- if: value为 false, 则:
- if: S为 false,
returnundefined; 否则抛出ReferenceError
- if: S为 false,
returnGet(bindingObject, N)
DeleteBinding ( N )
在object env中,只有绑定名称N所对应的bind object中的属性是[[Configurable]] = true时才可以删除
- let: bindingObject = env.[[BindingObject]]
returnbindingObject.[[Delete]] (N)
[[Delete]]方法的逻辑可参考标准:tc39.es/ecma262/#se…
HasThisBinding ( )
returnfalse
HasSuperBinding ( )
returnfalse
WithBaseObject ( )
- if: env.[[IsWithEnvironment]]为true,
returnenv.[[BindingObject]] - else:
returnundefined
Global Environment Record
Global Environment Record代表的是最外层的作用域,它提供了以下几种绑定:内置的全局对象,全局对象的属性和script元素内的所有顶层声明(注意:这里的script元素指的应该是非module的普通script元素)
Global Environment Record在逻辑上是一个单独的env,但是在标准定义中,它其实是一个 object Environment Record和 declarative Environment Record的组合体。
-
object Environment Record包含了全部的内置全局变量,我们代码中经常会出现的NaN,undefined,Infinity,还有parseInt, parseFloat方法,等等,这些都是包含在这个Environment Record的绑定之中的。结合with语句的使用(with语句所创建的就是一个object env),我们就可以明白在代码中为什么可以直接写NaN,而不需要写global.NaN。这些所有的属性或方法可以参考标准第19章(tc39.es/ecma262/#se…)
-
除了这些内置的全局变量之外,object Environment Record中还包括以下这些语法所声明的绑定:
函数声明、generator函数声明、异步函数声明(async)、异步generator函数声明和var声明。 -
除了上述的情况之外,其他在全局环境中的声明都包含在了declarative Environment Record中,例如全局环境下的let, const,class语句。
Global Environment Record的特有字段和方法
Global Environment Record有以下几个额外的字段:
| 字段名称 | 可选值 | 释义 |
|---|---|---|
| [[ObjectRecord]] | Object Environment Record | 即上文中提到的object Environment Record |
| [[GlobalThisValue]] | Object | 全局作用域中的this值,宿主环境可能提供任何对象作为this值 |
| [[DeclarativeRecord]] | Declarative Environment Record | 上文中提到的declarative Environment Record |
| [[VarNames]] | String[] | 全局作用域下由函数声明、generator函数声明、异步函数声明(async)、异步generator函数声明和var声明所产生的绑定名称的列表 |
Global Environment Record额外拥有的方法如下:
| 方法名称 | 释义 |
|---|---|
| GetThisBinding() | 返回env的this绑定值 |
| HasVarDeclaration (N) | 判断env中是否存在名称为N,并且是通过函数声明、generator函数声明、异步函数声明(async)、异步generator函数声明和var声明所创建的绑定 |
| HasLexicalDeclaration (N) | 判断env中是否存在名称为N,并且是通过词法声明所创建的绑定。词法声明包括let, const, class等 |
| HasRestrictedGlobalProperty (N) | |
| CanDeclareGlobalVar (N) | 判定CreateGlobalVarBinding(N)能否调用成功 |
| CanDeclareGlobalFunction (N) | 判定CreateGlobalFunctionBinding(N)能否调用成功 |
| CreateGlobalVarBinding(N, D) | 下文单独介绍 |
| CreateGlobalFunctionBinding(N, V, D) | 下文单独介绍 |
这里先重点介绍一下CreateGlobalVarBinding(N, D)和CreateGlobalFunctionBinding(N, V, D)这两个方法:
- CreateGlobalVarBinding(N, D)
用于在object Environment Record组件中创建并初始化名称为N的绑定,初始值为undefined。该绑定是一个可变绑定,如果D为true,代表该绑定可能会被删除。此外,全局对象还会拥有一个名称为N的属性,并且该属性也会被赋予相应的值
这一点就解释了为什么我们在全局作用域下通过var声明的变量可以通过“global.变量名称”进行访问
- CreateGlobalFunctionBinding(N, V, D)
用于在object Environment Record组件中创建并初始化一个函数绑定,V为初始化绑定值(即绑定的函数)。该绑定是一个可变绑定,如果D为true,代表该绑定可能会被删除。此外,全局对象还会拥有一个名称为N的属性,这个属性的值即为函数V
Global Environment Record方法的执行逻辑
HasBinding ( N )
- let: DclRec = env.[[DeclarativeRecord]]
- if: DclRec.HasBinding(N), 返回 true
- let: ObjRec = env.[[ObjectRecord]]
returnObjRec.HasBinding(N)
CreateMutableBinding ( N, D )
- let: DclRec = env.[[DeclarativeRecord]]
- if: DclRec.HasBinding(N)为true, 直接抛出TypeError
returnDclRec.CreateMutableBinding(N, D).
CreateImmutableBinding ( N, S )
和CreateMutableBinding类似,只是最后一步调用的是DeclarativeRecord的CreateImmutableBinding方法
InitializeBinding ( N, V )
- let: DclRec = env.[[DeclarativeRecord]]
- if: DclRec.HasBinding(N)为true
returnDclRec.InitializeBinding ( N, V )
- Assert: 如果名称为N的绑定存在,那么必须是存在于object Environment Record中
- let: ObjRec = env.[[ObjectRecord]]
returnObjRec.InitializeBinding(N, V)
SetMutableBinding ( N, V, S )
- let: DclRec = env.[[DeclarativeRecord]]
- if: DclRec.HasBinding(N)为true
returnDclRec.SetMutableBinding ( N, V, S )
- let: ObjRec = env.[[ObjectRecord]]
returnObjRec.SetMutableBinding ( N, V, S )
GetBindingValue ( N, S )
和上面的SetMutableBinding方法类似,只是调用的分别是DclRec和ObjRec的GetBindingValue方法
DeleteBinding ( N )
- let: DclRec = env.[[DeclarativeRecord]]
- if: DclRec.HasBinding(N)为true
- return DclRec.DeleteBinding ( N )
- let: ObjRec = env.[[ObjectRecord]]
- let: globalObject = ObjRec.[[BindingObject]]
- let: existingProp = HasOwnProperty(globalObject, N)
- if: existingProp = true:
- let:status = ObjRec.DeleteBinding(N)
- if: status为true:
- let: varNames = envRec.[[VarNames]]
- 如果N是varNames的一个元素,则将其从varNames中删除
returnstatus
returntrue
HasThisBinding ( )
-return true
global env是会提供this绑定的
HasSuperBinding ( )
returnfalse
WithBaseObject ( )
returnundefined 虽然global env中有一个object env组件,但是这个组件并不是通过with语句所创建的,因此总是返回undefined
GetThisBinding ( )
returnenv.[[GlobalThisValue]]
HasVarDeclaration ( N )
- let: varDeclaredNames = envRec.[[VarNames]]
- if: varDeclaredNames包含N,
则returntrue returnfalse
HasLexicalDeclaration ( N )
- let: DclRec = env.[[DeclarativeRecord]]
returnDclRec.HasBinding(N)
HasRestrictedGlobalProperty ( N )
用于判断标识符N是不是global object的属性,这个属性不能被全局的词法声明所覆盖
- let: ObjRec = env.[[ObjectRecord]]
- let: globalObject = ObjRec.[[BindingObject]]
- let: existingProp = globalObject.GetOwnProperty(N)
- if: existingProp为undefined,
returnfalse - if: existingProp.[[Configurable]]为true,
returnfalse returntrue
CanDeclareGlobalVar ( N )
- let: ObjRec = env.[[ObjectRecord]]
- let: globalObject = ObjRec.[[BindingObject]]
- let: hasProperty = HasOwnProperty(globalObject, N)
- if: hasProperty为true,
returntrue returnIsExtensible(globalObject)
IsExtensible可以理解为Object.isExtensible方法
CanDeclareGlobalFunction ( N )
- let: ObjRec = env.[[ObjectRecord]]
- let: globalObject = ObjRec.[[BindingObject]]
- let: existingProp = globalObject.GetOwnProperty(N)
- if: existingProp为undefined,return IsExtensible(globalObject)
- if: existingProp.[[Configurable]] 为true,
returntrue - If: IsDataDescriptor(existingProp) 为 true,并且 existingProp has attribute values { [[Writable]]: true, [[Enumerable]]: true },
returntrue -returnfalse
IsDataDescriptor(desc)的判定逻辑为:如果属性描述符desc既没有writable,也没有value属性,则为true;否则是false
CreateGlobalVarBinding ( N, D )
该方法是在global env的object Environment Record组件中创建一个可变绑定,并且在[[varNames]]记录中增加标识符N
- let: ObjRec = env.[[ObjectRecord]]
- let: globalObject = ObjRec.[[BindingObject]]
- let: hasProperty = HasOwnProperty(globalObject, N)
- let: extensible = IsExtensible(globalObject)
- If: hasProperty为 false,并且 extensible为 true, 则:
- 执行ObjRec.CreateMutableBinding(N, D)
- 执行ObjRec.InitializeBinding(N, undefined)
- let: varDeclaredNames = env.[[VarNames]]
- If: varDeclaredNames中还没有包含 N, 则将N添加到varDeclaredNames记录中
return
CreateGlobalFunctionBinding ( N, V, D )
- let: ObjRec = env.[[ObjectRecord]]
- let: globalObject = ObjRec.[[BindingObject]]
- let: existingProp = globalObject.GetOwnProperty(N)
- if: existingProp为 undefined 或者 existingProp.[[Configurable]]为 true, 则:
- let: 令desc为一个属性描述符 = PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D }
- 否则:
- let: 令desc为一个属性描述符 = PropertyDescriptor { [[Value]]: V }
- 执行: DefinePropertyOrThrow(globalObject, N, desc)
- 执行: Set(globalObject, N, V, false)
- let: varDeclaredNames = env.[[VarNames]]
- If: varDeclaredNames中还没有包含 N, 则将N添加到varDeclaredNames记录中
return