前面的文章—ECMA-262 规范第 6 节中 Language Types 翻译—翻译了 ECMA-262 规范的 ECMAScript Data Types and Values 章节的前半部分 Language Types,下面翻译后半部分 Specification Types。
翻译
规范类型
规范类型对应于算法中用于描述 ECMAScript 语言构造和 ECMAScript 语言类型的语义的元值。 规范类型包括 Reference、List、Completion、 Property Descriptor、 Lexical Environment、Environment Record 和 Data Block。 规范类型值是人造产物,不一定对应于 ECMAScript 实现中的任何特定实体。 规范类型值可以用来描述 ECMAScript 表达式计算的中间结果,但是这些值不能被存储为对象的属性或 ECMAScript 语言变量的值。
List 和 Record 规范类型
List 类型用于解释在 new 表达式、函数调用和其他需要简单有序值列表的算法中对参数列表(参见 12.3.6)的求值。 List 类型的值只是包含单个值的列表元素的有序序列。 这些序列可以是任意长度的。 可以使用 0-origin 索引随机访问列表的元素。 为了计数方便,可以使用类似数组的语法来访问 List 元素。 例如,arguments[2]是表示 List 参数的第 3 个元素的简写。
本规范中为了符号更方便,可以使用语法表示一个新的 List 值。 例如,« 1, 2 » 定义了一个 List 值,它有两个元素,每个元素都被初始化为一个特定的值。 一个新的空 List 可以表示为« »。
Record 类型用于描述本规范算法中的数据聚合。 Record 类型值由一个或多个命名字段组成。 每个字段的值要么是 ECMAScript 值,要么是由与 Record 类型关联的名称表示的抽象值。 字段名总是用双括号括起来,例如[[Value]]。
在本规范中,为了符号更方便,可以使用类似对象的语法来表示 Record 值。 例如,{[[ Field1]] : 42,[[ Field2]] : false,[[ Field3]] : empty }定义了一个 Record 值,该值有三个字段,每个字段都被初始化为一个特定的值。 字段名称顺序不重要。 任何未显式列出的字段都被认为是不存在的。
在规范文本和算法中,点符号可用于指代 record 值的特定字段。 例如,如果 R 是上一段中显示的 record,那么 R.[[Field2]]就是“名为[[Field2]]的 R 字段”的简写。
常用的 Record 字段组合的模式可以命名,该名称可以用作文本 Record 值的前缀,用于标识所描述的特定类型的聚合。 例如: PropertyDescriptor {[[ Value ]] : 42,[[[ Writable ]]] : false,[[ Configurable ]] : true }。
Set 和 Relation 规范类型
Set 类型用于解释内存模型中使用的无序元素集合。 Set 类型的值是元素的简单集合,其中任何元素都不会出现超过一次。 元素可以添加到Sets中,也可以从Sets中移除。 Sets可以相互合并、交叉或减去。
Relation类型用于解释Sets上的约束。 Relation 类型的值是有序对值(来自值域)的Sets。 例如,关于事件的 Relation 是一组事件的有序对。 对于一个Relation R 和的两个值 a 和 b(来自R的值域),a R b 简写为“有序对(a,b)是 R 的一个成员”。 当一个Relation是满足某些条件的最少Relation时,它对这些条件是最小的。
严格半序是满足下列条件的Relation值 R。
- 对于 R 域中的所有 a、 b 和 c:
- 不是a R a的情况, 并且
- 如果a R b 且b R c, 则a R c.
注意 1:上述两个性质按顺序称为非自反性和传递性。
严格全序是满足下列条件的Relation值 R。
- 对于 R 域中的所有 a、 b 和 c:
- a 等同于b 或者说是 a R b 或b R a, 并且
- 不是a R a的情况 ,并且
- 如果a R b 且b R c,那么a R c.
注意 2:上述三个性质依次称为总体性、非自反性和传递性。
Completion Record 规范类型
Completion 类型是一个 Record,在执行非本地控制权转移时用于解释执行值的运行时传递和控制流,例如statements的行为(break,
continue,
return和throw)。
Completion 类型的值是 Record 值,其字段由表8定义。 这些值称为Completion Records。
Field Name | Value | Meaning |
---|---|---|
[[Type]] | normal, break, continue, return或throw | 发生的completion的类型 |
[[Value]] | 任意 ECMAScript 语言类型值 或 空值 | 产生的值 |
[[Target]] | 任意ECMAScript String类型值 或空值 | 定向控制传输的目标label。 |
“abrupt completion”这个术语指的是任何带有[[Type]]值的非正常完成。
Await
下述的算法步骤:
- Let completion be Await(value).
等同于下述算法步骤:
- Let asyncContext be the running execution context.
- Let promise be ? PromiseResolve(%Promise%, « value »).
- Let stepsFulfilled be the algorithm steps defined in Await Fulfilled Functions.
- Let onFulfilled be CreateBuiltinFunction(stepsFulfilled, « [[AsyncContext]] »).
- Set onFulfilled.[[AsyncContext]] to asyncContext.
- Let stepsRejected be the algorithm steps defined in Await Rejected Functions.
- Let onRejected be CreateBuiltinFunction(stepsRejected, « [[AsyncContext]] »).
- Set onRejected.[[AsyncContext]] to asyncContext.
- Perform ! PerformPromiseThen(promise, onFulfilled, onRejected).
- Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
- Set the code evaluation state of asyncContext such that when evaluation is resumed with a Completion completion, the following steps of the algorithm that invoked Await will be performed, with completion available.
- Return.
- NOTE: This returns to the evaluation of the operation that had most previously resumed evaluation of asyncContext.
其中,除了completion之外,上述步骤中的所有变量都是临时的,只有在与 Await 相关的步骤中变量才可见。
注意:可以与? 和! 前缀结合使用,例如
- Let result be ? Await(value).
与下述步骤等同:
- Let result be Await(value).
- ReturnIfAbrupt(result).
Await Fulfilled 函数
Await fulfilled 函数是一个匿名的内置函数,它作为 Await 规范工具的一部分用于将promise fulfillment值作为正常completion交付给caller。 每个Await fulfilled的函数都有一个[[ AsyncContext ]]内部插槽。
当使用参数值调用Await fulfilled的函数时,将采取以下步骤:
- Let F be the active function object.
- Let asyncContext be F.[[AsyncContext]].
- Let prevContext be the running execution context.
- Suspend prevContext.
- Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
- Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it.
- Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
- Return undefined.
Await fulfilled函数的“ length”属性值是1。
Await Rejected 函数
Await rejected 函数是一个匿名的内置函数,用作 Await 规范工具的一部分,将promise rejection的reason作为一个abrupt throw completion交付给调用者。 每个 Await rejected 函数都有一个[[ AsyncContext ]]内部插槽。
当使用参数reason调用 Await rejected 函数时,将采取以下步骤:
- Let F be the active function object.
- Let asyncContext be F.[[AsyncContext]].
- Let prevContext be the running execution context.
- Suspend prevContext.
- Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
- Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that suspended it.
- Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
- Return undefined.
Await rejected函数的“length”属性值是1。
NormalCompletion
抽象操作 NormalCompletion 只有一个参数,例如:
- Return NormalCompletion(argument).
是如下定义的简写形式:
- Return Completion { [[Type]]: normal, [[Value]]: argument, [[Target]]: empty }.
ThrowCompletion
带有一个参数的抽象操作 ThrowCompletion,例如:
- Return ThrowCompletion(argument).
是如下定义的简写形式:
- Return Completion { [[Type]]: throw, [[Value]]: argument, [[Target]]: empty }.
UpdateEmpty ( completionRecord, value )
带completionRecord 和 value参数的 UpdateEmpty 抽象操作执行以下步骤:
- Assert: If completionRecord.[[Type]] is either return or throw, then completionRecord.[[Value]] is not empty.
- If completionRecord.[[Value]] is not empty, return Completion(completionRecord).
- Return Completion { [[Type]]: completionRecord.[[Type]], [[Value]]: value, [[Target]]: completionRecord.[[Target]] }.
Reference 规范类型
注意:Reference 类型用于解释诸如 delete、 typeof、赋值操作符、 super 关键字和其他语言特性等操作符的行为。 例如,赋值的左操作数应该产生引用。
Reference 是已解析的名称或属性绑定。 Reference 由三个组件组成: 基础值组件、引用名称组件和布尔值严格引用标志。 基础值组件是undefined、 Object、 Boolean、 String、 Symbol、 Number 或 Environment Record。 undefined的基础值组件表示Reference无法解析为绑定。 引用名称组件是 String 或 Symbol 值。
Super Reference 是一个 Reference,用于表示使用 Super 关键字表示的名称绑定。Super Reference有一个附加的 thisValue 组件,它的基础值组件永远不会是 Environment Record。
本规范使用下列抽象操作对reference 进行操作:
GetBase ( V )
GetReferencedName ( V )
IsStrictReference ( V )
HasPrimitiveBase ( V )
- Assert: Type(V) is Reference.
- If Type(V’s base value component) is Boolean, String, Symbol, or Number, return true; otherwise return false.
IsPropertyReference ( V )
- Assert: Type(V) is Reference.
- If either the base value component of V is an Object or HasPrimitiveBase(V) is true, return true; otherwise return false.
IsUnresolvableReference ( V )
- Assert: Type(V) is Reference.
- If the base value component of V is undefined, return true; otherwise return false.
IsSuperReference ( V )
GetValue ( V )
ReturnIfAbrupt(V).
Let base be GetBase(V).
If IsUnresolvableReference(V) is true, throw a ReferenceError exception.
If[IsPropertyReference(http://www.ecma-international.org/ecma-262/#sec-ispropertyreference)(V) is true, then
IfHasPrimitiveBase(V) is true, then
- Assert: In this case, base will never be undefined or null.
- Set base to ! ToObject(base).
- Return ? base.[Get], GetThisValue(V)).
Else base must be an Environment Record,
- Return ? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V)) (see 8.1.1).
PutValue ( V, W )
- ReturnIfAbrupt(V).
- ReturnIfAbrupt(W).
- If Type(V) is not Reference, throw a ReferenceError exception.
- Let base be GetBase(V).
- If IsUnresolvableReference(V) is true, then
- If IsStrictReference(V) is true, then
- Throw a ReferenceError exception.
- Let globalObj be GetGlobalObject().
- Return ? Set(globalObj, GetReferencedName(V), W, false).
- If IsStrictReference(V) is true, then
- Else if IsPropertyReference(V) is true, then
- If HasPrimitiveBase(V) is true, then
- Let succeeded be ? base.[Set], W, GetThisValue(V)).
- If succeeded is false and IsStrictReference(V) is true, throw a TypeError exception.
- Return.
- Else base must be an Environment Record,
- Return ? base.SetMutableBinding(GetReferencedName(V), W, IsStrictReference(V)) (see 8.1.1).
注意:在上述算法和普通对象[[Set]]内部方法之外不能访问在步骤6.1.2中可能创建的对象。 实现时可以选择避免实际创建该对象。
GetThisValue ( V )
- Assert: IsPropertyReference(V) is true.
- If IsSuperReference(V) is true, then
- Return the value of the thisValue component of the reference V.
- Return GetBase(V).
InitializeReferencedBinding ( V, W )
- ReturnIfAbrupt(V).
- ReturnIfAbrupt(W).
- Assert: Type(V) is Reference.
- Assert: IsUnresolvableReference(V) is false.
- Let base be GetBase(V).
- Assert: base is an Environment Record.
- Return base.InitializeBinding(GetReferencedName(V), W).
属性描述符规范类型
属性描述符类型用于解释对象 property 的attributes的操作和具体化。 属性描述符类型的值为Record。 每个字段的名称是一个属性名,其值是在6.1.7.1中指定的对应属性值。 此外,任何字段都可以存在或不存在。 此规范中用于标记属性描述符records文本描述的模式名称是“ PropertyDescriptor”。
根据具体字段的存在或使用,属性描述符值可以进一步分类为数据属性描述符和访问器属性描述符。 数据属性描述符包含任何名为[[[Value]]或[[Writable]]的字段。 访问器属性描述符包含任何名为[[ Get ]]或[[ Set ]]的字段。 任何属性描述符都可以有名为[[Enumerable]和[[Configurable]]的字段。 属性描述符值不能既是数据属性描述符又是访问器属性描述符; 但是,它可能既不是数据属性描述符也不是访问器属性描述符。 泛型属性描述符是既不是数据属性描述符也不是访问器属性描述符。 完全填充的属性描述符包含与表2或表3中定义的property attributes相对应的所有字段。
本规范中使用以下抽象操作对属性描述符值进行操作:
IsAccessorDescriptor ( Desc )
当使用属性描述符 Desc 调用抽象操作 IsAccessorDescriptor 时,将执行以下步骤:
- If Desc is undefined, return false.
- If both Desc.[[Get]] and Desc.[[Set]] are absent, return false.
- Return true.
IsDataDescriptor ( Desc )
当使用属性描述符 Desc 调用抽象操作 IsDataDescriptor时,将执行以下步骤:
- If Desc is undefined, return false.
- If both Desc.[[Value]] and Desc.[[Writable]] are absent, return false.
- Return true.
IsGenericDescriptor ( Desc )
当使用属性描述符 Desc 调用抽象操作 IsGenericDescriptor 时,将执行以下步骤:
- If Desc is undefined, return false.
- If IsAccessorDescriptor(Desc) and IsDataDescriptor(Desc) are both false, return true.
- Return false.
FromPropertyDescriptor ( Desc )
当使用属性描述符 Desc 调用抽象操作 FromPropertyDescriptor 时,将执行以下步骤:
- If Desc is undefined, return undefined.
- Let obj be ObjectCreate(%ObjectPrototype%).
- Assert: obj is an extensible ordinary object with no own properties.
- If Desc has a [[Value]] field, then
- Perform CreateDataProperty(obj,
"value"
, Desc.[[Value]]).
- Perform CreateDataProperty(obj,
- If Desc has a [[Writable]] field, then
- Perform CreateDataProperty(obj,
"writable"
, Desc.[[Writable]]).
- Perform CreateDataProperty(obj,
- If Desc has a [[Get]] field, then
- Perform CreateDataProperty(obj,
"get"
, Desc.[[Get]]).
- Perform CreateDataProperty(obj,
- If Desc has a [[Set]] field, then
- Perform CreateDataProperty(obj,
"set"
, Desc.[[Set]]).
- Perform CreateDataProperty(obj,
- If Desc has an [[Enumerable]] field, then
- Perform CreateDataProperty(obj,
"enumerable"
, Desc.[[Enumerable]]).
- Perform CreateDataProperty(obj,
- If Desc has a [[Configurable]] field, then
- Perform CreateDataProperty(obj,
"configurable"
, Desc.[[Configurable]]).
- Perform CreateDataProperty(obj,
- Assert: All of the above CreateDataProperty operations return true.
- Return obj.
ToPropertyDescriptor ( Obj )
当使用对象 Obj 调用抽象操作 ToPropertyDescriptor 时,将执行以下步骤:
- If Type(Obj) is not Object, throw a TypeError exception.
- Let desc be a new Property Descriptor that initially has no fields.
- Let hasEnumerable be ? HasProperty(Obj,
"enumerable"
). - If hasEnumerable is true, then
- Let hasConfigurable be ? HasProperty(Obj,
"configurable"
). - If hasConfigurable is true, then
- Let hasValue be ? HasProperty(Obj,
"value"
). - If hasValue is true, then
- Let value be ? Get(Obj,
"value"
). - Set desc.[[Value]] to value.
- Let value be ? Get(Obj,
- Let hasWritable be ? HasProperty(Obj,
"writable"
). - If hasWritable is true, then
- Let hasGet be ? HasProperty(Obj,
"get"
). - If hasGet is true, then
- Let getter be ? Get(Obj,
"get"
). - If IsCallable(getter) is false and getter is not undefined, throw a TypeError exception.
- Set desc.[[Get]] to getter.
- Let getter be ? Get(Obj,
- Let hasSet be ? HasProperty(Obj,
"set"
). - If hasSet is true, then
- Let setter be ? Get(Obj,
"set"
). - If IsCallable(setter) is false and setter is not undefined, throw a TypeError exception.
- Set desc.[[Set]] to setter.
- Let setter be ? Get(Obj,
- If desc.[[Get]] is present or desc.[[Set]] is present, then
- If desc.[[Value]] is present or desc.[[Writable]] is present, throw a TypeError exception.
- Return desc.
CompletePropertyDescriptor ( Desc )
当使用属性描述符 Desc 调用抽象操作 CompletePropertyDescriptor时,将执行以下步骤:
- Assert: Desc is a Property Descriptor.
- Let like be Record { [[Value]]: undefined, [[Writable]]: false, [[Get]]: undefined, [[Set]]: undefined, [[Enumerable]]: false, [[Configurable]]: false }.
- If IsGenericDescriptor(Desc) is true or IsDataDescriptor(Desc) is true, then
- If Desc does not have a [[Value]] field, set Desc.[[Value]] to like.[[Value]].
- If Desc does not have a [[Writable]] field, set Desc.[[Writable]] to like.[[Writable]].
- Else,
- If Desc does not have a [[Get]] field, set Desc.[[Get]] to like.[[Get]].
- If Desc does not have a [[Set]] field, set Desc.[[Set]] to like.[[Set]].
- If Desc does not have an [[Enumerable]] field, set Desc.[[Enumerable]] to like.[[Enumerable]].
- If Desc does not have a [[Configurable]] field, set Desc.[[Configurable]] to like.[[Configurable]].
- Return Desc.
词法环境和环境Record规范类型
词法环境和环境Record类型用于解释嵌套函数和块中的名称解析行为。 这些类型和对它们的操作在8.1中定义。
数据块
数据块规范类型用于描述一个不同的、可变的8位数值序列。 数据块值是用固定数量的字节创建的,每个字节的初始值为0。
在本规范中,为了计数方便,可以使用类似数组的语法来访问 Data Block 值的单个字节。 这种表示法将 Data Block 值表示为一个从0开始的的整数索引序列。 例如,如果 db 是一个5字节的数据块值,那么可以使用 db[2]来访问它的第3个字节。
驻留在内存中的、可以从多个代理并发引用的数据块被指定为共享数据块。 共享数据块具有一个无地址的标识(用于测试共享数据块的值是否相等) : 它不绑定到任何进程中映射到的虚拟地址,而是绑定到该块所代表的内存中的位置集。 只有当两个数据块所包含的位置集合相等时,它们才相等; 否则,它们不相等而且它们所包含的位置集合的交集为空。 最后,可以区分共享数据块和数据块。
内存模型使用共享数据块事件定义共享数据块的语义。 下面的抽象操作引入共享数据块事件,并充当计算语义和内存模型的事件语义之间的接口。 事件形成一个候选执行,内存模型在其中充当一个过滤器。 请参考内存模型以获得完整的语义。
共享数据块事件由内存模型中定义的 Records 建模。
本规范使用以下抽象操作对数据块值进行操作:
CreateByteDataBlock ( size )
当使用整数参数大小调用 CreateByteDataBlock 抽象操作时,将执行以下步骤:
- Assert: size ≥ 0.
- Let db be a new Data Block value consisting of size bytes. If it is impossible to create such a Data Block, throw a RangeError exception.
- Set all of the bytes of db to 0.
- Return db.
CreateSharedByteDataBlock ( size )
当使用整数参数大小调用 CreateSharedByteDataBlock 抽象操作时,将执行以下步骤:
- Assert: size ≥ 0.
- Let db be a new Shared Data Block value consisting of size bytes. If it is impossible to create such a Shared Data Block, throw a RangeError exception.
- Let execution be the [[CandidateExecution]] field of the surrounding agent‘s Agent Record.
- Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
- Let zero be « 0 ».
- For each index i of db, do
- Append WriteSharedMemory { [[Order]]:
"Init"
, [[NoTear]]: true, [[Block]]: db, [[ByteIndex]]: i, [[ElementSize]]: 1, [[Payload]]: zero } to eventList.
- Append WriteSharedMemory { [[Order]]:
- Return db.
CopyDataBlockBytes ( toBlock, toIndex, fromBlock, fromIndex, count )
当调用抽象操作CopyDataBlockBytes 时,将执行以下步骤:
- Assert: fromBlock and toBlock are distinct Data Block or Shared Data Block values.
- Assert: fromIndex, toIndex, and count are integer values ≥ 0.
- Let fromSize be the number of bytes in fromBlock.
- Assert: fromIndex + count ≤ fromSize.
- Let toSize be the number of bytes in toBlock.
- Assert: toIndex + count ≤ toSize.
- Repeat, while count > 0
- If fromBlock is a Shared Data Block, then
- Let execution be the [[CandidateExecution]] field of the surrounding agent‘s Agent Record.
- Let eventList be the [[EventList]] field of the element in execution.[[EventsRecords]] whose [[AgentSignifier]] is AgentSignifier().
- Let bytes be a List of length 1 that contains a nondeterministically chosen byte value.
- NOTE: In implementations, bytes is the result of a non-atomic read instruction on the underlying hardware. The nondeterminism is a semantic prescription of the memory model to describe observable behaviour of hardware with weak consistency.
- Let readEvent be ReadSharedMemory { [[Order]]:
"Unordered"
, [[NoTear]]: true, [[Block]]: fromBlock, [[ByteIndex]]: fromIndex, [[ElementSize]]: 1 }. - Append readEvent to eventList.
- Append Chosen Value Record { [[Event]]: readEvent, [[ChosenValue]]: bytes } to execution.[[ChosenValues]].
- If toBlock is a Shared Data Block, then
- Append WriteSharedMemory { [[Order]]:
"Unordered"
, [[NoTear]]: true, [[Block]]: toBlock, [[ByteIndex]]: toIndex, [[ElementSize]]: 1, [[Payload]]: bytes } to eventList.
- Append WriteSharedMemory { [[Order]]:
- Else,
- Set toBlock[toIndex] to bytes[0].
- Else,
- Assert: toBlock is not a Shared Data Block.
- Set toBlock[toIndex] to fromBlock[fromIndex].
- Increment toIndex and fromIndex each by 1.
- Decrement count by 1.
- If fromBlock is a Shared Data Block, then
- Return NormalCompletion(empty).
总结
翻译完后自己对规范类型的理解是:Specification Type是一个抽象的概念,只存在在规范里,并不真实存在在ECMAScript中。规范类型用来描述表达式求值过程的中间结果,是一种内部实现,也不对程序员直接开放。给了一些大致的自洽的数据结构来描述内部的机制,供设计JS引擎使用。