页面模式偏好

9 可执行代码和执行上下文

9.1 Environment Record

Environment Record 是一种规范类型,用于根据 ECMAScript 代码的词法嵌套结构定义 Identifier 与特定变量和函数之间的关联。通常,Environment Record 与 ECMAScript 代码的某些特定句法结构相关联,例如 FunctionDeclaration、BlockStatement 或 TryStatement 的 Catch 子句。每次对此类代码求值时,都会创建一个新的 Environment Record,以记录该代码创建的标识符绑定。

每个 Environment Record 都有一个 [[OuterEnv]] 字段,其值为 null 或对外层 Environment Record 的引用。它用于对 Environment Record 的逻辑嵌套进行建模。一个(内层)Environment Record 的外层引用,是对逻辑上包围该内层 Environment Record 的 Environment Record 的引用。当然,外层 Environment Record 也可以有自己的外层 Environment Record。一个 Environment Record 可以作为多个内层 Environment Record 的外层环境。例如,如果一个 FunctionDeclaration 包含两个嵌套的 FunctionDeclaration,那么每个嵌套函数的 Environment Record 都会以包围它的函数当前求值的 Environment Record 作为其外层 Environment Record。

Environment Record 纯粹是规范机制,无需对应于 ECMAScript 实现中的任何特定产物。ECMAScript 程序无法直接访问或操作此类值。

9.1.1 Environment Record 类型层次结构

可以将 Environment Record 视为存在于一个简单的面向对象层次结构中,其中 Environment Record 是一个抽象类,具有三个具体子类:Declarative Environment Record、Object Environment Record 和 Global Environment Record。Function Environment Record 和 Module Environment Record 是 Declarative Environment Record 的子类。

Environment Record 抽象类包含 表 15 中定义的抽象规范方法。这些抽象方法在每个具体子类中都有不同的具体算法。

表 15: Environment Records的抽象方法
方法 用途 定义
HasBinding ( name )

抽象方法 HasBinding,接收参数 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。

它确定 Environment Record 是否具有 name 的绑定。
它在以下类型中具有具体定义:
CreateMutableBinding ( name, deletable )

抽象方法 CreateMutableBinding,接收参数 name (String) 和 deletable (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。

它在 Environment Record 中创建一个新的、但尚未初始化的可变绑定。name 是被绑定名称的文本。如果 deletable 是 true,则该绑定随后可以被删除。
它在以下类型中具有具体定义:
CreateImmutableBinding ( name, strict )

抽象方法 CreateImmutableBinding,接收参数 name (String) 和 strict (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。

它在 Environment Record 中创建一个新的、但尚未初始化的不可变绑定。name 是被绑定名称的文本。如果 strict 是 true,那么在该绑定初始化后尝试设置其值时,无论引用该绑定的操作是否处于严格模式,都会抛出异常。
它在以下类型中具有具体定义:
InitializeBinding ( name, value )

抽象方法 InitializeBinding,接收参数 name (String) 和 value (ECMAScript 语言值);返回值:(正常完成 (值:unused) 或 抛出完成)。

它设置 Environment Record 中已存在但尚未初始化的绑定的值。name 是被绑定名称的文本。value 是该绑定的值。
它在以下类型中具有具体定义:
SetMutableBinding ( name, value, strict )

抽象方法 SetMutableBinding,接收参数 name (String)、value (ECMAScript 语言值) 和 strict (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。

它设置 Environment Record 中已存在的可变绑定的值。name 是被绑定名称的文本。value 是该绑定的值。如果 strict 是 true 且无法设置该绑定,则会抛出 TypeError 异常。
它在以下类型中具有具体定义:
GetBindingValue ( name, strict )

抽象方法 GetBindingValue,接收参数 name (String) 和 strict (Boolean);返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。

它从 Environment Record 中返回已存在绑定的值。name 是被绑定名称的文本。strict 用于标识源自严格模式代码或以其他方式要求严格模式引用语义的引用。如果 strict 是 true 且绑定不存在,则会抛出 ReferenceError 异常。如果绑定存在但尚未初始化,则无论 strict 的值如何,都会抛出 ReferenceError。
它在以下类型中具有具体定义:
DeleteBinding ( name )

抽象方法 DeleteBinding,接收参数 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。

它从 Environment Record 中删除一个绑定。name 是被绑定名称的文本。如果存在 name 的绑定,则移除该绑定并返回 true。如果绑定存在但无法移除,则返回 false。如果绑定不存在,则返回 true。
它在以下类型中具有具体定义:
HasThisBinding ( )

抽象方法 HasThisBinding,接收无参数;返回值:Boolean。

它确定 Environment Record 是否建立了 this 绑定。如果建立了则返回 true,否则返回 false。
它在以下类型中具有具体定义:
GetThisBinding ( )

抽象方法 GetThisBinding,接收无参数;返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。

它返回此 Environment Record 的 this 绑定值。如果 this 绑定尚未初始化,则抛出 ReferenceError。
它在以下类型中具有具体定义:
HasSuperBinding ( )

抽象方法 HasSuperBinding,接收无参数;返回值:Boolean。

它确定 Environment Record 是否建立了 super 方法绑定。如果建立了则返回 true,否则返回 false。如果返回 true,则意味着该 Environment Record 是 Function Environment Record,不过反过来并不成立。
它在以下类型中具有具体定义:
WithBaseObject ( )

抽象方法 WithBaseObject,接收无参数;返回值:(Object 或 undefined)。

如果此 Environment Record 与 with 语句相关联,则返回该 with 对象。否则返回 undefined。
它在以下类型中具有具体定义:

9.1.1.1 Declarative Environment Record

每个 Declarative Environment Record 都与一个 ECMAScript 程序作用域相关联,该作用域包含变量、常量、let、类、模块、导入和/或函数声明。Declarative Environment Record 绑定其作用域中所包含声明定义的一组标识符。

每个 Declarative Environment Record 还有一个 [[DisposableResourceStack]] 字段,其中包含 DisposableResource Record 的 List。此列表的元素由 using 声明和 await using 声明进行跟踪,并且必须在构造该 Environment Record 的 Evaluation 步骤完成时释放。

9.1.1.1.1 HasBinding ( name )

a Declarative Environment Record envRecord的具体方法 HasBinding,接收参数 name (String);返回值:正常完成 (值:Boolean)。 它确定参数标识符是否为该 Record 绑定的标识符之一。 调用时执行以下步骤:

  1. 如果 envRecord 具有 name 的绑定,则返回 true。
  2. 返回 false。

9.1.1.1.2 CreateMutableBinding ( name, deletable )

a Declarative Environment Record envRecord的具体方法 CreateMutableBinding,接收参数 name (String) 和 deletable (Boolean);返回值:正常完成 (值:unused)。 它为名称 name 创建一个新的、尚未初始化的可变绑定。此 Environment Record 中不得已经存在 name 的绑定。如果 deletable 是 true,则将新绑定标记为可被删除。 调用时执行以下步骤:

  1. 断言:envRecord 尚未具有 name 的绑定。
  2. 在 envRecord 中为 name 创建一个可变绑定,并记录它尚未初始化。如果 deletable 是 true,则记录新创建的绑定可以通过后续的 DeleteBinding 调用被删除。
  3. 返回 unused。

9.1.1.1.3 CreateImmutableBinding ( name, strict )

a Declarative Environment Record envRecord的具体方法 CreateImmutableBinding,接收参数 name (String) 和 strict (Boolean);返回值:正常完成 (值:unused)。 它为名称 name 创建一个新的、尚未初始化的不可变绑定。此 Environment Record 中不得已经存在 name 的绑定。如果 strict 是 true,则将新绑定标记为严格绑定。 调用时执行以下步骤:

  1. 断言:envRecord 尚未具有 name 的绑定。
  2. 在 envRecord 中为 name 创建一个不可变绑定,并记录它尚未初始化。如果 strict 是 true,则记录新创建的绑定是严格绑定。
  3. 返回 unused。

9.1.1.1.4 InitializeBinding ( name, value )

a Declarative Environment Record envRecord的具体方法 InitializeBinding,接收参数 name (String) 和 value (ECMAScript 语言值);返回值:正常完成 (值:unused)。 它用于将名称为 name 的标识符当前绑定的绑定值设置为 value。必须已经存在一个尚未初始化的 name 绑定。 调用时执行以下步骤:

  1. 断言:envRecord 必须具有一个尚未初始化的 name 绑定。
  2. 将 envRecord 中 name 的绑定值设置为 value。
  3. 记录 envRecord 中 name 的绑定已经初始化。
  4. 返回 unused。

9.1.1.1.5 SetMutableBinding ( name, value, strict )

a Declarative Environment Record envRecord的具体方法 SetMutableBinding,接收参数 name (String)、value (ECMAScript 语言值) 和 strict (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。 它尝试将名称为 name 的标识符当前绑定的绑定值更改为 value。通常已经存在 name 的绑定,但在极少数情况下也可能不存在。如果该绑定是不可变绑定,并且 strict 是 true,则抛出 TypeError。 调用时执行以下步骤:

  1. 如果 envRecord 不具有 name 的绑定,则
    1. 如果 strict 是 true,则抛出 ReferenceError 异常。
    2. 执行 ! envRecord.CreateMutableBinding(name, true)。
    3. 执行 ! envRecord.InitializeBinding(name, value)。
    4. 返回 unused。
  2. 如果 envRecord 中 name 的绑定是严格绑定,则将 strict 设置为 true。
  3. 如果 envRecord 中 name 的绑定尚未初始化,则
    1. 抛出 ReferenceError 异常。
  4. 否则如果 envRecord 中 name 的绑定是可变绑定,则
    1. 将其绑定值更改为 value。
  5. 否则,
    1. 断言:这是一次更改不可变绑定值的尝试。
    2. 如果 strict 是 true,则抛出 TypeError 异常。
  6. 返回 unused。
注

会在步骤 1 中导致缺失绑定的 ECMAScript 代码示例如下:

function f() { eval("var x; x = (delete x, 0);"); }

9.1.1.1.6 GetBindingValue ( name, strict )

a Declarative Environment Record envRecord的具体方法 GetBindingValue,接收参数 name (String) 和 strict (Boolean);返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。 它返回名称为 name 的已绑定标识符的值。如果绑定存在但尚未初始化,则无论 strict 的值如何,都会抛出 ReferenceError。 调用时执行以下步骤:

  1. 断言:envRecord 具有 name 的绑定。
  2. 如果 envRecord 中 name 的绑定是尚未初始化的绑定,则抛出 ReferenceError 异常。
  3. 返回 envRecord 中当前绑定到 name 的值。

9.1.1.1.7 DeleteBinding ( name )

a Declarative Environment Record envRecord的具体方法 DeleteBinding,接收参数 name (String);返回值:正常完成 (值:Boolean)。 它只能删除已被明确指定为可删除的绑定。 调用时执行以下步骤:

  1. 断言:envRecord 具有 name 的绑定。
  2. 如果 envRecord 中 name 的绑定无法删除,则返回 false。
  3. 从 envRecord 中移除 name 的绑定。
  4. 返回 true。

9.1.1.1.8 HasThisBinding ( )

a Declarative Environment Record envRecord的具体方法 HasThisBinding,接收无参数;返回值:false。 调用时执行以下步骤:

  1. 返回 false。
注

普通 Declarative Environment Record(即既不是 Function Environment Record,也不是 Module Environment Record)不提供 this 绑定。

9.1.1.1.9 GetThisBinding ( )

本规范从不使用 Declarative Environment Record 的 GetThisBinding 具体方法。

9.1.1.1.10 HasSuperBinding ( )

a Declarative Environment Record envRecord的具体方法 HasSuperBinding,接收无参数;返回值:false。 调用时执行以下步骤:

  1. 返回 false。
注

普通 Declarative Environment Record(即既不是 Function Environment Record,也不是 Module Environment Record)不提供 super 绑定。

9.1.1.1.11 WithBaseObject ( )

a Declarative Environment Record envRecord的具体方法 WithBaseObject,接收无参数;返回值:undefined。 调用时执行以下步骤:

  1. 返回 undefined。

9.1.1.2 Object Environment Record

每个 Object Environment Record 都与一个称为其绑定对象的对象相关联。Object Environment Record 绑定一组字符串标识符名称,这些名称直接对应于其绑定对象的属性名称。不属于 IdentifierName 形式的 String 的属性键不包含在被绑定标识符集合中。无论属性的 [[Enumerable]] 特性如何设置,自有属性和继承属性都会包含在该集合中。由于属性可以动态添加到对象或从对象删除,因此 Object Environment Record 所绑定的标识符集合可能会因任何添加或删除属性的操作产生的副作用而发生变化。因这种副作用而创建的任何绑定都被视为可变绑定,即使对应属性的 Writable 特性是 false。Object Environment Record 不存在不可变绑定。

为 with 语句(14.11)创建的 Object Environment Record 可以将其绑定对象作为函数调用中使用的隐式 this 值。此能力由 Boolean [[IsWithEnvironment]] 字段控制。

Object Environment Record 具有 表 16 中列出的附加状态字段。

表 16: Object Environment Record 的附加字段
字段名称 值 含义
[[BindingObject]] Object 此 Environment Record 的绑定对象。
[[IsWithEnvironment]] Boolean 指示此 Environment Record 是否是为 with 语句创建的。

9.1.1.2.1 HasBinding ( name )

an Object Environment Record envRecord的具体方法 HasBinding,接收参数 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。 它确定其关联的绑定对象是否具有名称为 name 的属性。 调用时执行以下步骤:

  1. 令 bindingObj 为 envRecord.[[BindingObject]]。
  2. 令 foundBinding 为 ? HasProperty(bindingObj, name)。
  3. 如果 foundBinding 是 false,则返回 false。
  4. 如果 envRecord.[[IsWithEnvironment]] 是 false,则返回 true。
  5. 令 unscopables 为 ? Get(bindingObj, %Symbol.unscopables%)。
  6. 如果 unscopables 是 Object,则
    1. 令 blocked 为 ToBoolean(? Get(unscopables, name))。
    2. 如果 blocked 是 true,则返回 false。
  7. 返回 true。

9.1.1.2.2 CreateMutableBinding ( name, deletable )

an Object Environment Record envRecord的具体方法 CreateMutableBinding,接收参数 name (String) 和 deletable (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。 它在 Environment Record 关联的绑定对象中创建一个名称为 name 的属性,并将其初始化为值 undefined。如果 deletable 是 true,则将新属性的 [[Configurable]] 特性设置为 true;否则设置为 false。 调用时执行以下步骤:

  1. 令 bindingObj 为 envRecord.[[BindingObject]]。
  2. 执行 ? DefinePropertyOrThrow(bindingObj, name, PropertyDescriptor { [[Value]]: undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: deletable })。
  3. 返回 unused。
注

通常 envRecord 不会具有 name 的绑定,但如果确实存在,DefinePropertyOrThrow 的语义可能会导致现有绑定被替换或遮蔽,也可能导致返回突然完成。

9.1.1.2.3 CreateImmutableBinding ( name, strict )

本规范从不使用 Object Environment Record 的 CreateImmutableBinding 具体方法。

9.1.1.2.4 InitializeBinding ( name, value )

an Object Environment Record envRecord的具体方法 InitializeBinding,接收参数 name (String) 和 value (ECMAScript 语言值);返回值:(正常完成 (值:unused) 或 抛出完成)。 它用于将名称为 name 的标识符当前绑定的绑定值设置为 value。 调用时执行以下步骤:

  1. 执行 ? envRecord.SetMutableBinding(name, value, false)。
  2. 返回 unused。
注

在本规范中,对 Object Environment Record 使用 CreateMutableBinding 后,都会立即针对相同名称调用 InitializeBinding。因此,本规范不会显式跟踪 Object Environment Record 中绑定的初始化状态。

9.1.1.2.5 SetMutableBinding ( name, value, strict )

an Object Environment Record envRecord的具体方法 SetMutableBinding,接收参数 name (String)、value (ECMAScript 语言值) 和 strict (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。 它尝试将 Environment Record 关联绑定对象中名称为 name 的属性值设置为 value。通常名为 name 的属性已经存在,但如果不存在或当前不可写,则错误处理方式由 strict 决定。 调用时执行以下步骤:

  1. 令 bindingObj 为 envRecord.[[BindingObject]]。
  2. 令 stillExists 为 ? HasProperty(bindingObj, name)。
  3. 如果 stillExists 是 false 且 strict 是 true,则抛出 ReferenceError 异常。
  4. 执行 ? Set(bindingObj, name, value, strict)。
  5. 返回 unused。

9.1.1.2.6 GetBindingValue ( name, strict )

an Object Environment Record envRecord的具体方法 GetBindingValue,接收参数 name (String) 和 strict (Boolean);返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。 它返回其关联绑定对象中名称为 name 的属性值。该属性通常应当已经存在,但如果不存在,则结果取决于 strict。 调用时执行以下步骤:

  1. 令 bindingObj 为 envRecord.[[BindingObject]]。
  2. 令 value 为 ? HasProperty(bindingObj, name)。
  3. 如果 value 是 false,则
    1. 如果 strict 是 false,则返回 undefined。
    2. 抛出 ReferenceError 异常。
  4. 返回 ? Get(bindingObj, name)。

9.1.1.2.7 DeleteBinding ( name )

an Object Environment Record envRecord的具体方法 DeleteBinding,接收参数 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。 它只能删除对应于环境对象中 [[Configurable]] 特性值为 true 的属性的绑定。 调用时执行以下步骤:

  1. 令 bindingObj 为 envRecord.[[BindingObject]]。
  2. 返回 ? bindingObj.[[Delete]](name)。

9.1.1.2.8 HasThisBinding ( )

an Object Environment Record envRecord的具体方法 HasThisBinding,接收无参数;返回值:false。 调用时执行以下步骤:

  1. 返回 false。
注

Object Environment Record 不提供 this 绑定。

9.1.1.2.9 GetThisBinding ( )

本规范从不使用 Object Environment Record 的 GetThisBinding 具体方法。

9.1.1.2.10 HasSuperBinding ( )

an Object Environment Record envRecord的具体方法 HasSuperBinding,接收无参数;返回值:false。 调用时执行以下步骤:

  1. 返回 false。
注

Object Environment Record 不提供 super 绑定。

9.1.1.2.11 WithBaseObject ( )

an Object Environment Record envRecord的具体方法 WithBaseObject,接收无参数;返回值:(Object 或 undefined)。 调用时执行以下步骤:

  1. 如果 envRecord.[[IsWithEnvironment]] 是 true,则返回 envRecord.[[BindingObject]]。
  2. 返回 undefined。

9.1.1.3 Function Environment Record

Function Environment Record 是一种 Declarative Environment Record,用于表示函数的顶层作用域,并且如果该函数不是 ArrowFunction 函数或 AsyncArrowFunction 函数,则提供 this 绑定。如果函数不是 ArrowFunction 函数或 AsyncArrowFunction 函数并且引用了 super,则其 Function Environment Record 还包含用于从函数内部执行 super 方法调用的状态。

Function Environment Record 具有 表 17 中列出的附加状态字段。

表 17: Function Environment Record 的附加字段
字段名称 值 含义
[[ThisValue]] ECMAScript 语言值 这是此次函数调用所使用的 this 值。
[[ThisBindingStatus]] lexical、initialized 或 uninitialized 如果值为 lexical,则这是 ArrowFunction 或 AsyncArrowFunction,并且没有局部 this 值。
[[FunctionObject]] ECMAScript 函数对象 其调用导致创建此 Environment Record 的函数对象。
[[NewTarget]] 构造函数或 undefined 如果此 Environment Record 是由 [[Construct]] 内部方法创建的,则 [[NewTarget]] 是 [[Construct]] 的 newTarget 参数值。否则,其值为 undefined。

Function Environment Record 支持 表 15 中列出的所有 Declarative Environment Record 方法,并且除 HasThisBinding、GetThisBinding 和 HasSuperBinding 外,所有这些方法都共享相同的规范。

9.1.1.3.1 BindThisValue ( envRecord, value )

抽象操作 BindThisValue,接收参数 envRecord (Function Environment 记录) 和 value (ECMAScript 语言值);返回值:(正常完成 (值:unused) 或 抛出完成)。 它设置 envRecord.[[ThisValue]],并记录它已经初始化。 调用时执行以下步骤:

  1. 断言:envRecord.[[ThisBindingStatus]] 不是 lexical。
  2. 如果 envRecord.[[ThisBindingStatus]] 是 initialized,则抛出 ReferenceError 异常。
  3. 将 envRecord.[[ThisValue]] 设置为 value。
  4. 将 envRecord.[[ThisBindingStatus]] 设置为 initialized。
  5. 返回 unused。

9.1.1.3.2 HasThisBinding ( )

a Function Environment Record envRecord的具体方法 HasThisBinding,接收无参数;返回值:Boolean。 调用时执行以下步骤:

  1. 如果 envRecord.[[ThisBindingStatus]] 是 lexical,则返回 false。
  2. 返回 true。

9.1.1.3.3 GetThisBinding ( )

a Function Environment Record envRecord的具体方法 GetThisBinding,接收无参数;返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。 调用时执行以下步骤:

  1. 断言:envRecord.[[ThisBindingStatus]] 不是 lexical。
  2. 如果 envRecord.[[ThisBindingStatus]] 是 uninitialized,则抛出 ReferenceError 异常。
  3. 返回 envRecord.[[ThisValue]]。

9.1.1.3.4 HasSuperBinding ( )

a Function Environment Record envRecord的具体方法 HasSuperBinding,接收无参数;返回值:Boolean。 调用时执行以下步骤:

  1. 如果 envRecord.[[ThisBindingStatus]] 是 lexical,则返回 false。
  2. 如果 envRecord.[[FunctionObject]].[[HomeObject]] 是 undefined,则返回 false。
  3. 返回 true。

9.1.1.3.5 GetSuperBase ( envRecord )

抽象操作 GetSuperBase,接收参数 envRecord (Function Environment 记录);返回值:(Object、null 或 undefined)。 它返回作为绑定在 envRecord 中的 super 属性访问之基对象的对象。值 undefined 表示此类访问将产生运行时错误。 调用时执行以下步骤:

  1. 令 home 为 envRecord.[[FunctionObject]].[[HomeObject]]。
  2. 如果 home 是 undefined,则返回 undefined。
  3. 断言:home 是普通对象。
  4. 返回 ! home.[[GetPrototypeOf]]()。

9.1.1.4 Global Environment Record

Global Environment Record 用于表示由在同一 Realm 中处理的所有 ECMAScript Script 元素共享的最外层作用域。Global Environment Record 为内置全局项(条款 19)、全局对象的属性,以及 Script 中出现的所有顶层声明(8.2.11、8.2.13)提供绑定。

Global Environment Record 在逻辑上是单一 Record,但规范将其定义为封装 Object Environment Record 和 Declarative Environment Record 的组合体。Object Environment Record 以关联 Realm Record 的全局对象作为其基对象。此全局对象就是 Global Environment Record 的 GetThisBinding 具体方法所返回的值。Global Environment Record 的 Object Environment Record 组成部分包含所有内置全局项(条款 19)的绑定,以及全局代码中包含的 FunctionDeclaration、GeneratorDeclaration、AsyncFunctionDeclaration、AsyncGeneratorDeclaration 或 VariableStatement 所引入的所有绑定。全局代码中所有其他 ECMAScript 声明的绑定都包含在 Global Environment Record 的 Declarative Environment Record 组成部分中。

可以直接在全局对象上创建属性。因此,Global Environment Record 的 Object Environment Record 组成部分可能同时包含由 FunctionDeclaration、GeneratorDeclaration、AsyncFunctionDeclaration、AsyncGeneratorDeclaration 或 VariableDeclaration 声明显式创建的绑定,以及作为全局对象属性隐式创建的绑定。

Global Environment Record 具有 表 18 中列出的附加字段。

表 18: Global Environment Record 的附加字段
字段名称 值 含义
[[ObjectRecord]] Object Environment Record 绑定对象是全局对象。它包含全局内置绑定,以及关联 Realm 的全局代码中的 FunctionDeclaration、GeneratorDeclaration、AsyncFunctionDeclaration、AsyncGeneratorDeclaration 和 VariableDeclaration 绑定。
[[GlobalThisValue]] Object 全局作用域中 this 返回的值。宿主可以提供任何 ECMAScript Object 值。
[[DeclarativeRecord]] Declarative Environment Record 包含关联 Realm 的全局代码中除 FunctionDeclaration、GeneratorDeclaration、AsyncFunctionDeclaration、AsyncGeneratorDeclaration 和 VariableDeclaration 绑定之外的所有声明绑定。

9.1.1.4.1 HasBinding ( name )

a Global Environment Record envRecord的具体方法 HasBinding,接收参数 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。 它确定参数标识符是否为该 Record 所绑定的标识符之一。 调用时执行以下步骤:

  1. 令 declRecord 为 envRecord.[[DeclarativeRecord]]。
  2. 如果 ! declRecord.HasBinding(name) 是 true,则返回 true。
  3. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  4. 返回 ? objRecord.HasBinding(name)。

9.1.1.4.2 CreateMutableBinding ( name, deletable )

a Global Environment Record envRecord的具体方法 CreateMutableBinding,接收参数 name (String) 和 deletable (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。 它为名称 name 创建一个新的、尚未初始化的可变绑定。该绑定在关联的 DeclarativeRecord 中创建。DeclarativeRecord 中不得已经存在 name 的绑定。如果 deletable 是 true,则将新绑定标记为可被删除。 调用时执行以下步骤:

  1. 令 declRecord 为 envRecord.[[DeclarativeRecord]]。
  2. 如果 ! declRecord.HasBinding(name) 是 true,则抛出 TypeError 异常。
  3. 返回 ! declRecord.CreateMutableBinding(name, deletable)。

9.1.1.4.3 CreateImmutableBinding ( name, strict )

a Global Environment Record envRecord的具体方法 CreateImmutableBinding,接收参数 name (String) 和 strict (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。 它为名称 name 创建一个新的、尚未初始化的不可变绑定。此 Environment Record 中不得已经存在 name 的绑定。如果 strict 是 true,则将新绑定标记为严格绑定。 调用时执行以下步骤:

  1. 令 declRecord 为 envRecord.[[DeclarativeRecord]]。
  2. 如果 ! declRecord.HasBinding(name) 是 true,则抛出 TypeError 异常。
  3. 返回 ! declRecord.CreateImmutableBinding(name, strict)。

9.1.1.4.4 InitializeBinding ( name, value )

a Global Environment Record envRecord的具体方法 InitializeBinding,接收参数 name (String) 和 value (ECMAScript 语言值);返回值:(正常完成 (值:unused) 或 抛出完成)。 它用于将名称为 name 的标识符当前绑定的绑定值设置为 value。必须已经存在一个尚未初始化的 name 绑定。 调用时执行以下步骤:

  1. 令 declRecord 为 envRecord.[[DeclarativeRecord]]。
  2. 如果 ! declRecord.HasBinding(name) 是 true,则
    1. 返回 ! declRecord.InitializeBinding(name, value)。
  3. 断言:如果绑定存在,则它必须位于 Object Environment Record 中。
  4. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  5. 返回 ? objRecord.InitializeBinding(name, value)。

9.1.1.4.5 SetMutableBinding ( name, value, strict )

a Global Environment Record envRecord的具体方法 SetMutableBinding,接收参数 name (String)、value (ECMAScript 语言值) 和 strict (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。 它尝试将名称为 name 的标识符当前绑定的绑定值更改为 value。如果绑定是不可变绑定并且 strict 是 true,则抛出 TypeError。通常名为 name 的绑定已经存在,但如果不存在或当前不可写,则错误处理方式由 strict 决定。 调用时执行以下步骤:

  1. 令 declRecord 为 envRecord.[[DeclarativeRecord]]。
  2. 如果 ! declRecord.HasBinding(name) 是 true,则
    1. 返回 ? declRecord.SetMutableBinding(name, value, strict)。
  3. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  4. 返回 ? objRecord.SetMutableBinding(name, value, strict)。

9.1.1.4.6 GetBindingValue ( name, strict )

a Global Environment Record envRecord的具体方法 GetBindingValue,接收参数 name (String) 和 strict (Boolean);返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。 它返回名称为 name 的已绑定标识符的值。如果绑定是尚未初始化的绑定,则会抛出 ReferenceError 异常。通常名为 name 的绑定已经存在,但如果不存在或当前不可写,则错误处理方式由 strict 决定。 调用时执行以下步骤:

  1. 令 declRecord 为 envRecord.[[DeclarativeRecord]]。
  2. 如果 ! declRecord.HasBinding(name) 是 true,则
    1. 返回 ? declRecord.GetBindingValue(name, strict)。
  3. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  4. 返回 ? objRecord.GetBindingValue(name, strict)。

9.1.1.4.7 DeleteBinding ( name )

a Global Environment Record envRecord的具体方法 DeleteBinding,接收参数 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。 它只能删除已被明确指定为可删除的绑定。 调用时执行以下步骤:

  1. 令 declRecord 为 envRecord.[[DeclarativeRecord]]。
  2. 如果 ! declRecord.HasBinding(name) 是 true,则
    1. 返回 ! declRecord.DeleteBinding(name)。
  3. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  4. 令 globalObj 为 objRecord.[[BindingObject]]。
  5. 令 existingProperty 为 ? HasOwnProperty(globalObj, name)。
  6. 如果 existingProperty 是 true,则
    1. 返回 ? objRecord.DeleteBinding(name)。
  7. 返回 true。

9.1.1.4.8 HasThisBinding ( )

a Global Environment Record envRecord的具体方法 HasThisBinding,接收无参数;返回值:true。 调用时执行以下步骤:

  1. 返回 true。
注

Global Environment Record 始终提供 this 绑定。

9.1.1.4.9 GetThisBinding ( )

a Global Environment Record envRecord的具体方法 GetThisBinding,接收无参数;返回值:正常完成 (值:Object)。 调用时执行以下步骤:

  1. 返回 envRecord.[[GlobalThisValue]]。

9.1.1.4.10 HasSuperBinding ( )

a Global Environment Record envRecord的具体方法 HasSuperBinding,接收无参数;返回值:false。 调用时执行以下步骤:

  1. 返回 false。
注

Global Environment Record 不提供 super 绑定。

9.1.1.4.11 WithBaseObject ( )

a Global Environment Record envRecord的具体方法 WithBaseObject,接收无参数;返回值:undefined。 调用时执行以下步骤:

  1. 返回 undefined。

9.1.1.4.12 HasLexicalDeclaration ( envRecord, name )

抽象操作 HasLexicalDeclaration,接收参数 envRecord (Global Environment 记录) 和 name (String);返回值:Boolean。 它确定参数标识符在 envRecord 中是否具有由 LexicalDeclaration 或 ClassDeclaration 等词法声明创建的绑定。 调用时执行以下步骤:

  1. 令 declRecord 为 envRecord.[[DeclarativeRecord]]。
  2. 返回 ! declRecord.HasBinding(name)。

9.1.1.4.13 HasRestrictedGlobalProperty ( envRecord, name )

抽象操作 HasRestrictedGlobalProperty,接收参数 envRecord (Global Environment 记录) 和 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。 它确定参数标识符是否为全局对象上不得被全局词法绑定遮蔽的属性名称。 调用时执行以下步骤:

  1. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  2. 令 globalObj 为 objRecord.[[BindingObject]]。
  3. 令 existingProperty 为 ? globalObj.[[GetOwnProperty]](name)。
  4. 如果 existingProperty 是 undefined,则返回 false。
  5. 如果 existingProperty.[[Configurable]] 是 true,则返回 false。
  6. 返回 true。
注

全局对象上可能存在直接创建而不是通过 var 或函数声明来声明的属性。不能创建与全局对象不可配置属性同名的全局词法绑定。全局属性 "undefined" 就是此类属性的一个示例。

9.1.1.4.14 CanDeclareGlobalVar ( envRecord, name )

抽象操作 CanDeclareGlobalVar,接收参数 envRecord (Global Environment 记录) 和 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。 它确定如果使用相同参数 name 调用相应的 CreateGlobalVarBinding,该调用是否会成功。允许冗余的 var 声明以及针对预先存在的全局对象属性的 var 声明。 调用时执行以下步骤:

  1. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  2. 令 globalObj 为 objRecord.[[BindingObject]]。
  3. 令 hasProperty 为 ? HasOwnProperty(globalObj, name)。
  4. 如果 hasProperty 是 true,则返回 true。
  5. 返回 ? IsExtensible(globalObj)。

9.1.1.4.15 CanDeclareGlobalFunction ( envRecord, name )

抽象操作 CanDeclareGlobalFunction,接收参数 envRecord (Global Environment 记录) 和 name (String);返回值:(正常完成 (值:Boolean) 或 抛出完成)。 它确定如果使用相同参数 name 调用相应的 CreateGlobalFunctionBinding,该调用是否会成功。 调用时执行以下步骤:

  1. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  2. 令 globalObj 为 objRecord.[[BindingObject]]。
  3. 令 existingProperty 为 ? globalObj.[[GetOwnProperty]](name)。
  4. 如果 existingProperty 是 undefined,则返回 ? IsExtensible(globalObj)。
  5. 如果 existingProperty.[[Configurable]] 是 true,则返回 true。
  6. 如果 IsDataDescriptor(existingProperty) 是 true,并且 existingProperty 的特性值为 { [[Writable]]: true, [[Enumerable]]: true },则返回 true。
  7. 返回 false。

9.1.1.4.16 CreateGlobalVarBinding ( envRecord, name, deletable )

抽象操作 CreateGlobalVarBinding,接收参数 envRecord (Global Environment 记录)、name (String) 和 deletable (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。 它在关联的 Object Environment Record 中创建并初始化一个可变绑定。如果绑定已经存在,则复用该绑定,并假定它已初始化。 调用时执行以下步骤:

  1. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  2. 令 globalObj 为 objRecord.[[BindingObject]]。
  3. 令 hasProperty 为 ? HasOwnProperty(globalObj, name)。
  4. 令 extensible 为 ? IsExtensible(globalObj)。
  5. 如果 hasProperty 是 false 且 extensible 是 true,则
    1. 执行 ? objRecord.CreateMutableBinding(name, deletable)。
    2. 执行 ? objRecord.InitializeBinding(name, undefined)。
  6. 返回 unused。

9.1.1.4.17 CreateGlobalFunctionBinding ( envRecord, name, value, deletable )

抽象操作 CreateGlobalFunctionBinding,接收参数 envRecord (Global Environment 记录)、name (String)、value (ECMAScript 函数对象) 和 deletable (Boolean);返回值:(正常完成 (值:unused) 或 抛出完成)。 它在关联的 Object Environment Record 中创建并初始化一个可变绑定。如果绑定已经存在,则替换该绑定。 调用时执行以下步骤:

  1. 令 objRecord 为 envRecord.[[ObjectRecord]]。
  2. 令 globalObj 为 objRecord.[[BindingObject]]。
  3. 令 existingProperty 为 ? globalObj.[[GetOwnProperty]](name)。
  4. 如果 existingProperty 是 undefined 或 existingProperty.[[Configurable]] 是 true,则
    1. 令 propertyDesc 为 PropertyDescriptor { [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: deletable }。
  5. 否则,
    1. 令 propertyDesc 为 PropertyDescriptor { [[Value]]: value }。
  6. 执行 ? DefinePropertyOrThrow(globalObj, name, propertyDesc)。
  7. 执行 ? Set(globalObj, name, value, false)。
  8. 返回 unused。
注

全局函数声明始终表示为全局对象的自有属性。如果可能,会重新配置现有自有属性,使其具有一组标准特性值。步骤 7 等价于调用 InitializeBinding 具体方法所执行的操作,并且如果 globalObj 是 Proxy,将产生相同的 Proxy 陷阱调用序列。

9.1.1.5 Module Environment Record

Module Environment Record 是一种 Declarative Environment Record,用于表示 ECMAScript Module 的外层作用域。除了普通的可变和不可变绑定之外,Module Environment Record 还提供不可变导入绑定,这类绑定会间接访问另一个 Environment Record 中存在的目标绑定。

Module Environment Record 支持 表 15 中列出的所有 Declarative Environment Record 方法,并且除 GetBindingValue、DeleteBinding、HasThisBinding 和 GetThisBinding 外,所有这些方法都共享相同的规范。

9.1.1.5.1 GetBindingValue ( name, strict )

a Module Environment Record envRecord的具体方法 GetBindingValue,接收参数 name (String) 和 strict (Boolean);返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。 它返回名称为 name 的已绑定标识符的值。但是,如果该绑定是间接绑定,则返回目标绑定的值。如果绑定存在但尚未初始化,则抛出 ReferenceError。 调用时执行以下步骤:

  1. 断言:strict 是 true。
  2. 断言:envRecord 具有 name 的绑定。
  3. 如果 name 的绑定是间接绑定,则
    1. 令 module 和 targetName 为创建 name 的此绑定时所提供的间接引用值。
    2. 令 targetEnv 为 module.[[Environment]]。
    3. 如果 targetEnv 是 empty,则抛出 ReferenceError 异常。
    4. 返回 ? targetEnv.GetBindingValue(targetName, true)。
  4. 如果 envRecord 中 name 的绑定是尚未初始化的绑定,则抛出 ReferenceError 异常。
  5. 返回 envRecord 中当前绑定到 name 的值。
注

因为 Module 始终是严格模式代码,所以 strict 始终为 true。

9.1.1.5.2 DeleteBinding ( name )

本规范从不使用 Module Environment Record 的 DeleteBinding 具体方法。

注

Module Environment Record 仅在严格模式代码中使用,并且提前错误规则会阻止在严格模式代码中将 delete 运算符应用于会解析到 Module Environment Record 绑定的 Reference Record。参见 13.5.1.1。

9.1.1.5.3 HasThisBinding ( )

a Module Environment Record envRecord的具体方法 HasThisBinding,接收无参数;返回值:true。 调用时执行以下步骤:

  1. 返回 true。
注

Module Environment Record 始终提供 this 绑定。

9.1.1.5.4 GetThisBinding ( )

a Module Environment Record envRecord的具体方法 GetThisBinding,接收无参数;返回值:正常完成 (值:undefined)。 调用时执行以下步骤:

  1. 返回 undefined。

9.1.1.5.5 CreateImportBinding ( envRecord, name, targetModule, targetName )

抽象操作 CreateImportBinding,接收参数 envRecord (Module Environment 记录)、name (String)、targetModule (Module 记录) 和 targetName (String);返回值:unused。 它为名称 name 创建一个新的、已初始化的不可变间接绑定。envRecord 中不得已经存在 name 的绑定。targetName 是 targetModule 的 Module Environment Record 中存在的绑定名称。访问新绑定的值时,将间接访问目标绑定的绑定值。 调用时执行以下步骤:

  1. 断言:envRecord 尚未具有 name 的绑定。
  2. 断言:当 targetModule.[[Environment]] 被实例化时,它将具有 targetName 的直接绑定。
  3. 在 envRecord 中为 name 创建一个不可变间接绑定,以 targetModule 和 targetName 作为其目标绑定,并记录该绑定已初始化。
  4. 返回 unused。

9.1.2 Environment Record 操作

本规范使用以下抽象操作来操作 Environment Record:

9.1.2.1 GetIdentifierReference ( envRecord, name, strict )

抽象操作 GetIdentifierReference,接收参数 envRecord ((Environment 记录 或 null))、name (String) 和 strict (Boolean);返回值:(正常完成 (值:Reference 记录) 或 抛出完成)。 调用时执行以下步骤:

  1. 如果 envRecord 是 null,则
    1. 返回 Reference Record { [[Base]]: unresolvable, [[ReferencedName]]: name, [[Strict]]: strict, [[ThisValue]]: empty }。
  2. 令 exists 为 ? envRecord.HasBinding(name)。
  3. 如果 exists 是 true,则
    1. 返回 Reference Record { [[Base]]: envRecord, [[ReferencedName]]: name, [[Strict]]: strict, [[ThisValue]]: empty }。
  4. 令 outer 为 envRecord.[[OuterEnv]]。
  5. 返回 ? GetIdentifierReference(outer, name, strict)。

9.1.2.2 NewDeclarativeEnvironment ( outerEnv )

抽象操作 NewDeclarativeEnvironment,接收参数 outerEnv ((Environment 记录 或 null));返回值:Declarative Environment 记录。 调用时执行以下步骤:

  1. 令 envRecord 为不包含任何绑定的新 Declarative Environment Record。
  2. 将 envRecord.[[OuterEnv]] 设置为 outerEnv。
  3. 将 envRecord.[[DisposableResourceStack]] 设置为新的空 List。
  4. 返回 envRecord。

9.1.2.3 NewObjectEnvironment ( obj, isWithEnv, outerEnv )

抽象操作 NewObjectEnvironment,接收参数 obj (Object)、isWithEnv (Boolean) 和 outerEnv ((Environment 记录 或 null));返回值:Object Environment 记录。 调用时执行以下步骤:

  1. 令 envRecord 为新的 Object Environment Record。
  2. 将 envRecord.[[BindingObject]] 设置为 obj。
  3. 将 envRecord.[[IsWithEnvironment]] 设置为 isWithEnv。
  4. 将 envRecord.[[OuterEnv]] 设置为 outerEnv。
  5. 返回 envRecord。

9.1.2.4 NewFunctionEnvironment ( func, newTarget )

抽象操作 NewFunctionEnvironment,接收参数 func (ECMAScript 函数对象) 和 newTarget ((Object 或 undefined));返回值:Function Environment 记录。 调用时执行以下步骤:

  1. 令 envRecord 为不包含任何绑定的新 Function Environment Record。
  2. 将 envRecord.[[FunctionObject]] 设置为 func。
  3. 如果 func.[[ThisMode]] 是 lexical,则将 envRecord.[[ThisBindingStatus]] 设置为 lexical。
  4. 否则,将 envRecord.[[ThisBindingStatus]] 设置为 uninitialized。
  5. 将 envRecord.[[NewTarget]] 设置为 newTarget。
  6. 将 envRecord.[[OuterEnv]] 设置为 func.[[Environment]]。
  7. 将 envRecord.[[DisposableResourceStack]] 设置为新的空 List。
  8. 返回 envRecord。

9.1.2.5 NewGlobalEnvironment ( obj, thisValue )

抽象操作 NewGlobalEnvironment,接收参数 obj (Object) 和 thisValue (Object);返回值:Global Environment 记录。 调用时执行以下步骤:

  1. 令 objRecord 为 NewObjectEnvironment(obj, false, null)。
  2. 令 declRecord 为 NewDeclarativeEnvironment(null)。
  3. 令 envRecord 为新的 Global Environment Record。
  4. 将 envRecord.[[ObjectRecord]] 设置为 objRecord。
  5. 将 envRecord.[[GlobalThisValue]] 设置为 thisValue。
  6. 将 envRecord.[[DeclarativeRecord]] 设置为 declRecord。
  7. 将 envRecord.[[OuterEnv]] 设置为 null。
  8. 返回 envRecord。

9.1.2.6 NewModuleEnvironment ( outerEnv )

抽象操作 NewModuleEnvironment,接收参数 outerEnv (Global Environment 记录);返回值:Module Environment 记录。 调用时执行以下步骤:

  1. 令 envRecord 为不包含任何绑定的新 Module Environment Record。
  2. 将 envRecord.[[OuterEnv]] 设置为 outerEnv。
  3. 将 envRecord.[[DisposableResourceStack]] 设置为新的空 List。
  4. 返回 envRecord。

9.2 PrivateEnvironment Record

PrivateEnvironment Record 是一种规范机制,用于根据 ECMAScript 代码中 ClassDeclaration 和 ClassExpression 的词法嵌套结构跟踪 Private Name。它们与 Environment Record 类似,但彼此不同。每个 PrivateEnvironment Record 都与一个 ClassDeclaration 或 ClassExpression 相关联。每次对此类类进行求值时,都会创建一个新的 PrivateEnvironment Record,以记录该类声明的 Private Name。

每个 PrivateEnvironment Record 都具有 表 19 中定义的字段。

表 19: PrivateEnvironment Record 字段
字段名称 值类型 含义
[[OuterPrivateEnvironment]] PrivateEnvironment Record 或 null 最近的包含类的 PrivateEnvironment Record。如果与此 PrivateEnvironment Record 关联的类未包含在任何其他类中,则为 null。
[[Names]] Private Name 的 List 此类声明的 Private Name。

9.2.1 PrivateEnvironment Record 操作

本规范使用以下抽象操作来操作 PrivateEnvironment Record:

9.2.1.1 NewPrivateEnvironment ( outerPrivateEnv )

抽象操作 NewPrivateEnvironment,接收参数 outerPrivateEnv ((PrivateEnvironment 记录 或 null));返回值:PrivateEnvironment 记录。 调用时执行以下步骤:

  1. 令 names 为新的空 List。
  2. 返回 PrivateEnvironment Record { [[OuterPrivateEnvironment]]: outerPrivateEnv, [[Names]]: names }。

9.2.1.2 ResolvePrivateIdentifier ( privateEnv, identifier )

抽象操作 ResolvePrivateIdentifier,接收参数 privateEnv (PrivateEnvironment 记录) 和 identifier (String);返回值:私有名称。 调用时执行以下步骤:

  1. 令 names 为 privateEnv.[[Names]]。
  2. 对 names 的每个 Private Name privateName,执行
    1. 如果 privateName.[[Description]] 是 identifier,则
      1. 返回 privateName。
  3. 令 outerPrivateEnv 为 privateEnv.[[OuterPrivateEnvironment]]。
  4. 断言:outerPrivateEnv 不是 null。
  5. 返回 ResolvePrivateIdentifier(outerPrivateEnv, identifier)。

9.3 Realm

所有 ECMAScript 代码在求值之前都必须与一个 Realm 相关联。从概念上讲,Realm 由一组内在对象、一个 ECMAScript 全局环境、加载到该全局环境作用域中的所有 ECMAScript 代码,以及其他关联的状态和资源组成。

本规范使用 Realm Record 来表示 Realm,其字段在 表 20 中规定:

表 20: Realm Record 字段
字段名称 值 含义
[[AgentSignifier]] 代理标识符 拥有此 Realm 的代理
[[Intrinsics]] 字段名称为内在对象键、字段值为对象的 Record 与此 Realm 关联的代码所使用的内在值
[[GlobalObject]] Object 此 Realm 的全局对象
[[GlobalEnv]] Global Environment Record 此 Realm 的全局环境
[[TemplateMap]] 字段为 [[Site]](TemplateLiteral Parse Node)和 [[Array]](Array)的 Record 的 List

每个 Realm 使用其 Realm Record 的 [[TemplateMap]] 分别对模板对象进行规范化。每个 [[Site]] 值都是一个 TemplateLiteral Parse Node。关联的 [[Array]] 值是传递给标签函数的相应模板对象。

注 1
一旦 Parse Node 变得不可达,对应的 [[Array]] 也将不可达;如果实现从 [[TemplateMap]] 列表中移除该对,则不会被观察到。
[[LoadedModules]] LoadedModuleRequest Record 的 List

从此 Realm 导入的说明符字符串到已解析 Module Record 的映射。该列表不会包含两个不同的 Record r1 和 r2,使得 ModuleRequestsEqual(r1, r2) 为 true。

注 2
如 HostLoadImportedModule(16.2.1.10 注 1)中所述,Realm Record 中的 [[LoadedModules]] 仅在没有活动脚本或模块的上下文中运行 import() 表达式时使用。
[[HostDefined]] 任意值(默认值为 undefined) 为需要将附加信息与 Realm Record 关联的宿主保留的字段。

9.3.1 InitializeHostDefinedRealm ( )

抽象操作 InitializeHostDefinedRealm,接收无参数;返回值:(正常完成 (值:unused) 或 抛出完成)。 调用时执行以下步骤:

  1. 令 realm 为新的 Realm Record。
  2. 执行 CreateIntrinsics(realm)。
  3. 将 realm.[[AgentSignifier]] 设置为 AgentSignifier()。
  4. 将 realm.[[TemplateMap]] 设置为新的空 List。
  5. 令 newContext 为新的执行上下文。
  6. 将 newContext 的 Function 设置为 null。
  7. 将 newContext 的 Realm 设置为 realm。
  8. 将 newContext 的 ScriptOrModule 设置为 null。
  9. 将 newContext 压入执行上下文栈;newContext 现在是正在运行的执行上下文。
  10. 如果宿主要求使用特定对象作为 realm 的全局对象,则
    1. 令 global 为以宿主定义方式创建的此类对象。
  11. 否则,
    1. 令 global 为 OrdinaryObjectCreate(realm.[[Intrinsics]].[[%Object.prototype%]])。
  12. 如果宿主要求 realm 全局作用域中的 this 绑定返回一个不同于全局对象的对象,则
    1. 令 thisValue 为以宿主定义方式创建的此类对象。
  13. 否则,
    1. 令 thisValue 为 global。
  14. 将 realm.[[GlobalObject]] 设置为 global。
  15. 将 realm.[[GlobalEnv]] 设置为 NewGlobalEnvironment(global, thisValue)。
  16. 执行 ? SetDefaultGlobalBindings(realm)。
  17. 在 global 上创建任何宿主定义的全局对象属性。
  18. 返回 unused。

9.3.2 CreateIntrinsics ( realmRecord )

抽象操作 CreateIntrinsics,接收参数 realmRecord (Realm 记录);返回值:unused。 调用时执行以下步骤:

  1. 将 realmRecord.[[Intrinsics]] 设置为新的 Record。
  2. 使用 表 6 中列出的值设置 realmRecord.[[Intrinsics]] 的字段。字段名称是该表“内在对象名称”列中列出的名称。每个字段的值都是一个新的对象值,并根据条款 19 到 28 中各对象的规范,以属性值完整且递归地填充。所有对象属性值都是新创建的对象值。所有属于内置函数对象的值,都通过执行 CreateBuiltinFunction(steps, length, name, slots, realmRecord, proto, async) 创建,其中 steps 是本规范提供的该函数定义,name 是函数 "name" 属性的初始值,length 是函数 "length" 属性的初始值,slots 是函数所规定内部槽名称的列表(如果有),proto 是函数 [[Prototype]] 内部槽的规定值,而当函数被描述为“async”时 async 为 true,否则为 false。内在对象及其属性的创建必须按顺序进行,以避免依赖尚未创建的对象。
  3. 执行 AddRestrictedFunctionProperties(realmRecord.[[Intrinsics]].[[%Function.prototype%]], realmRecord)。
  4. 返回 unused。

9.3.3 SetDefaultGlobalBindings ( realmRecord )

抽象操作 SetDefaultGlobalBindings,接收参数 realmRecord (Realm 记录);返回值:(正常完成 (值:unused) 或 抛出完成)。 调用时执行以下步骤:

  1. 令 global 为 realmRecord.[[GlobalObject]]。
  2. 对条款 19 中规定的 Global Object 的每个属性,执行
    1. 令 name 为属性名称的 String 值。
    2. 令 propertyDesc 为该属性完全填充的数据 Property Descriptor,其中包含为该属性规定的特性。对于 19.2、19.3 或 19.4 中列出的属性,[[Value]] 特性的值是 realmRecord 中对应的内在对象。
    3. 执行 ? DefinePropertyOrThrow(global, name, propertyDesc)。
  3. 返回 unused。

9.4 执行上下文

执行上下文是一种规范机制,用于跟踪 ECMAScript 实现对代码的运行时求值。在任意时刻,每个代理最多只有一个实际正在执行代码的执行上下文。它称为该代理的正在运行的执行上下文。本规范中对正在运行的执行上下文的所有引用,都表示周围代理正在运行的执行上下文。

执行上下文栈用于跟踪执行上下文。正在运行的执行上下文始终是此栈的顶部元素。每当控制从与当前正在运行的执行上下文关联的可执行代码转移到与该执行上下文不关联的可执行代码时,都会创建新的执行上下文。新创建的执行上下文会被压入栈中,并成为正在运行的执行上下文。

执行上下文包含跟踪其关联代码执行进度所需的任何实现特定状态。每个执行上下文至少具有 表 21 中列出的状态组成部分。

表 21: 所有执行上下文的状态组成部分
组成部分 用途
代码求值状态 执行、暂停和恢复与此执行上下文关联代码的求值所需的任何状态。
Function 如果此执行上下文正在对函数对象的代码求值,则此组成部分的值是该函数对象。如果该上下文正在对 Script 或 Module 的代码求值,则该值为 null。
Realm 关联代码通过其访问 ECMAScript 资源的 Realm Record。
ScriptOrModule 关联代码所源自的 Module Record 或 Script Record。如果没有源脚本或模块,例如 InitializeHostDefinedRealm 中创建的原始执行上下文,则值为 null。

正在运行的执行上下文对代码的求值可能会在本规范定义的多个位置暂停。正在运行的执行上下文暂停后,另一个执行上下文可以成为正在运行的执行上下文并开始对其代码求值。稍后,已暂停的执行上下文可以再次成为正在运行的执行上下文,并从先前暂停的位置继续对其代码求值。正在运行的执行上下文状态在各执行上下文之间的转换通常采用类似栈的后进先出方式。但是,某些 ECMAScript 特性要求正在运行的执行上下文进行非 LIFO 转换。

正在运行的执行上下文的 Realm 组成部分的值也称为当前 Realm Record。正在运行的执行上下文的 Function 组成部分的值也称为活动函数对象。

ECMAScript 代码执行上下文具有 表 22 中列出的附加状态组成部分。

表 22: ECMAScript 代码执行上下文的附加状态组成部分
组成部分 用途
LexicalEnvironment 标识用于解析此执行上下文中的代码所作标识符引用的 Environment Record。
VariableEnvironment 标识保存此执行上下文中 VariableStatement 创建的绑定的 Environment Record。
PrivateEnvironment 标识保存最近包含类中 ClassElement 创建的 Private Name 的 PrivateEnvironment Record。如果没有包含类,则为 null。

执行上下文的 LexicalEnvironment 和 VariableEnvironment 组成部分始终是 Environment Record。

表示 Generator 求值的执行上下文具有 表 23 中列出的附加状态组成部分。

表 23: Generator 执行上下文的附加状态组成部分
组成部分 用途
Generator 此执行上下文正在求值的 Generator。

在大多数情况下,本规范中的算法只会直接操作正在运行的执行上下文(执行上下文栈的顶部)。因此,当不加限定地使用“LexicalEnvironment”和“VariableEnvironment”这些术语时,它们指的是正在运行的执行上下文中的相应组成部分。

执行上下文纯粹是规范机制,无需对应于 ECMAScript 实现中的任何特定产物。ECMAScript 代码无法直接访问或观察执行上下文。

9.4.1 GetActiveScriptOrModule ( )

抽象操作 GetActiveScriptOrModule,接收无参数;返回值:(Script 记录、Module 记录 或 null)。 它用于根据正在运行的执行上下文确定正在运行的脚本或模块。 调用时执行以下步骤:

  1. 如果执行上下文栈为空,则返回 null。
  2. 令 executionContext 为执行上下文栈中 ScriptOrModule 组成部分不是 null 的最顶层执行上下文。
  3. 如果不存在这样的执行上下文,则返回 null。
  4. 返回 executionContext 的 ScriptOrModule。

9.4.2 ResolveBinding ( name [ , envRecord ] )

抽象操作 ResolveBinding,接收参数 name (String)和可选参数 envRecord ((Environment 记录 或 undefined));返回值:(正常完成 (值:Reference 记录) 或 抛出完成)。 它用于确定 name 的绑定。envRecord 可用于显式提供要在其中搜索绑定的 Environment Record。 调用时执行以下步骤:

  1. 如果不存在 envRecord 或 envRecord 是 undefined,则
    1. 将 envRecord 设置为正在运行的执行上下文的 LexicalEnvironment。
  2. 断言:envRecord 是 Environment Record。
  3. 令 strict 为 IsStrict(正在求值的句法产生式)。
  4. 返回 ? GetIdentifierReference(envRecord, name, strict)。
注

ResolveBinding 的结果始终是一个 Reference Record,其 [[ReferencedName]] 字段为 name。

9.4.3 GetThisEnvironment ( )

抽象操作 GetThisEnvironment,接收无参数;返回值:Environment 记录。 它查找当前提供关键字 this 绑定的 Environment Record。 调用时执行以下步骤:

  1. 令 envRecord 为正在运行的执行上下文的 LexicalEnvironment。
  2. 重复执行,
    1. 令 exists 为 envRecord.HasThisBinding()。
    2. 如果 exists 是 true,则返回 envRecord。
    3. 令 outer 为 envRecord.[[OuterEnv]]。
    4. 断言:outer 不是 null。
    5. 将 envRecord 设置为 outer。
注

步骤 2 中的循环始终会终止,因为环境列表始终以具有 this 绑定的全局环境结束。

9.4.4 ResolveThisBinding ( )

抽象操作 ResolveThisBinding,接收无参数;返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。 它使用正在运行的执行上下文的 LexicalEnvironment 确定关键字 this 的绑定。 调用时执行以下步骤:

  1. 令 envRecord 为 GetThisEnvironment()。
  2. 返回 ? envRecord.GetThisBinding()。

9.4.5 GetNewTarget ( )

抽象操作 GetNewTarget,接收无参数;返回值:(Object 或 undefined)。 它使用正在运行的执行上下文的 LexicalEnvironment 确定 NewTarget 值。 调用时执行以下步骤:

  1. 令 envRecord 为 GetThisEnvironment()。
  2. 断言:envRecord 具有 [[NewTarget]] 字段。
  3. 返回 envRecord.[[NewTarget]]。

9.4.6 GetGlobalObject ( )

抽象操作 GetGlobalObject,接收无参数;返回值:Object。 它返回当前正在运行的执行上下文所使用的全局对象。 调用时执行以下步骤:

  1. 令 currentRealm 为当前 Realm Record。
  2. 返回 currentRealm.[[GlobalObject]]。

9.4.7 RunSuspendedContext ( context, completionRecord )

抽象操作 RunSuspendedContext,接收参数 context (执行上下文) 和 completionRecord (完成记录);返回值:(正常完成 (值:(ECMAScript 语言值 或 unused)) 或 突兀完成)。 它恢复 context(将 completionRecord 作为恢复值传给它),并等待结果。 调用时执行以下步骤:

  1. 令 callerContext 为正在运行的执行上下文。
  2. 暂停 callerContext。
  3. 将 context 压入执行上下文栈;context 现在是正在运行的执行上下文。
  4. 恢复 context 中已暂停的求值,将 completionRecord 作为导致其暂停的操作的结果传入。令 result 为恢复后的计算传出的 Completion Record。
  5. 断言:到达此步骤时,context 已经从执行上下文栈中移除,并且 callerContext 再次成为正在运行的执行上下文。
  6. 返回 Completion(result)。

9.4.8 RunCallerContext ( value )

抽象操作 RunCallerContext,接收参数 value ((ECMAScript 语言值 或 empty));返回值:完成记录。 它恢复调用方上下文(将 value 作为恢复值传给它),并等待结果(如果有)。 调用时执行以下步骤:

  1. 令 genContext 为正在运行的执行上下文。
  2. 从执行上下文栈中移除 genContext,并将执行上下文栈顶部的执行上下文恢复为正在运行的执行上下文。
  3. 令 callerContext 为正在运行的执行上下文。
  4. 恢复 callerContext,传入 NormalCompletion(value)。
  5. 注:上述步骤将控制权转移到 callerContext 并暂停。要使其解除暂停并让控制继续执行本算法中的后续步骤,唯一的方法是再次恢复 genContext,而这可能永远不会发生。
  6. 断言:genContext 是正在运行的执行上下文。
  7. 令 result 为刚刚用于恢复 genContext 的 Completion Record。
  8. 返回 Completion(result)。

9.5 Job 和将 Job 入队的宿主操作

Job 是一个没有参数的 Abstract Closure,当当前没有其他 ECMAScript 计算正在进行时,它会启动一次 ECMAScript 计算。

Job 由 ECMAScript 宿主环境安排在特定代理中执行。本规范描述了用于安排 Job 的宿主钩子 HostEnqueueGenericJob、HostEnqueueFinalizationRegistryCleanupJob、HostEnqueuePromiseJob 和 HostEnqueueTimeoutJob。本规范中的宿主钩子按照对 Job 调度施加的附加约束进行组织。宿主可以定义其他用于安排 Job 的抽象操作。此类操作接受 Job Abstract Closure 和 Realm(Realm Record 或 null)作为参数。如果提供 Realm Record,则这些操作会安排该 Job 在将来的某个时间,在拥有该 Realm 的代理中的该 Realm 内执行。如果为 Realm 提供的是 null,则该 Job 不会对 ECMAScript 代码求值。它们的实现必须符合以下要求:

注 1
宿主环境无需在调度方面统一处理 Job。例如,Web 浏览器和 Node.js 将 Promise 处理 Job 视为比其他工作优先级更高;未来的特性可能会添加不会以如此高优先级处理的 Job。

在任意特定时刻,如果满足以下所有条件,则 scriptOrModule(Script Record、Module Record 或 null)是活动脚本或模块:

在任意特定时刻,如果满足以下所有条件,则一次执行被称为已准备好对 ECMAScript 代码求值:

注 2

宿主环境可以通过将执行上下文压入执行上下文栈,使一次执行准备好对代码求值。具体步骤由实现定义。

具体选择哪个 Realm 由宿主环境决定。这个初始执行上下文和 Realm 仅在调用任何回调函数之前使用。当调用与 Job 相关的回调函数(例如 Promise 处理器)时,该调用会压入其自己的执行上下文和 Realm。

特定种类的 Job 具有附加符合性要求。

9.5.1 JobCallback Record

JobCallback Record 是用于存储函数对象和宿主定义值的 Record。通过宿主入队的 Job 调用的函数对象可能具有附加的宿主定义上下文。为了传播该状态,Job Abstract Closure 不应直接捕获并调用函数对象。应改用 HostMakeJobCallback 和 HostCallJobCallback。

注

例如,WHATWG HTML 规范(https://html.spec.whatwg.org/)使用宿主定义值来传播 Promise 回调的 incumbent settings object。

JobCallback Record 具有 表 24 中列出的字段。

表 24: JobCallback Record 字段
字段名称 值 含义
[[Callback]] 函数对象 调用 Job 时要调用的函数。
[[HostDefined]] 任意值(默认值为 empty) 为宿主使用而保留的字段。

9.5.2 HostMakeJobCallback ( callback )

宿主定义的抽象操作 HostMakeJobCallback,接收参数 callback (函数对象);返回值:JobCallback 记录。

HostMakeJobCallback 的实现必须符合以下要求:

HostMakeJobCallback 的默认实现在被调用时执行以下步骤:

  1. 返回 JobCallback Record { [[Callback]]: callback, [[HostDefined]]: empty }。

不是 Web 浏览器的 ECMAScript 宿主必须使用 HostMakeJobCallback 的默认实现。

注

这是在回调传递给负责最终安排并运行它的函数时调用的。例如,promise.then(thenAction) 会在调用 Promise.prototype.then 时对 thenAction 调用 MakeJobCallback,而不是在安排 reaction Job 时。

9.5.3 HostCallJobCallback ( jobCallback, thisValue, argList )

宿主定义的抽象操作 HostCallJobCallback,接收参数 jobCallback (JobCallback 记录)、thisValue (ECMAScript 语言值) 和 argList (列表 (元素:ECMAScript 语言值));返回值:(正常完成 (值:ECMAScript 语言值) 或 抛出完成)。

HostCallJobCallback 的实现必须符合以下要求:

  • 它必须执行并返回 Call(jobCallback.[[Callback]], thisValue, argList) 的结果。
注

此要求意味着宿主不能更改本规范中定义的函数对象的 [[Call]] 行为。

HostCallJobCallback 的默认实现在被调用时执行以下步骤:

  1. 断言:IsCallable(jobCallback.[[Callback]]) 是 true。
  2. 返回 ? Call(jobCallback.[[Callback]], thisValue, argList)。

不是 Web 浏览器的 ECMAScript 宿主必须使用 HostCallJobCallback 的默认实现。

9.5.4 HostEnqueueGenericJob ( job, realm )

宿主定义的抽象操作 HostEnqueueGenericJob,接收参数 job (a Job Abstract Closure) 和 realm (Realm 记录);返回值:unused。 它安排 job 在将来的某个时间,在由 realm.[[AgentSignifier]] 所指示代理中的 Realm realm 内执行。与此算法一起使用的 Abstract Closure 旨在不受优先级和顺序等附加约束地进行调度。

HostEnqueueGenericJob 的实现必须符合 9.5 中的要求。

9.5.5 HostEnqueuePromiseJob ( job, realm )

宿主定义的抽象操作 HostEnqueuePromiseJob,接收参数 job (a Job Abstract Closure) 和 realm ((Realm 记录 或 null));返回值:unused。 它安排 job 在将来的某个时间执行。与此算法一起使用的 Abstract Closure 旨在与 Promise 的处理相关,或者以与 Promise 处理操作相同的优先级进行调度。

HostEnqueuePromiseJob 的实现必须符合 9.5 中的要求以及以下要求:

注

由 NewPromiseResolveThenableJob 返回的 Job 的 realm 通常是对 then 函数对象调用 GetFunctionRealm 的结果。由 NewPromiseReactionJob 返回的 Job 的 realm 通常是当处理器不是 undefined 时对该处理器调用 GetFunctionRealm 的结果。如果处理器是 undefined,则 realm 为 null。对于这两种 Job,当 GetFunctionRealm 突然完成(即针对已撤销的 Proxy 调用)时,realm 是调用 GetFunctionRealm 时的当前 Realm Record。当 realm 为 null 时,不会对任何用户 ECMAScript 代码求值,也不会创建任何新的 ECMAScript 对象(例如 Error 对象)。例如,WHATWG HTML 规范(https://html.spec.whatwg.org/)使用 realm 来检查运行脚本的能力以及 entry 概念。

9.5.6 HostEnqueueTimeoutJob ( timeoutJob, realm, milliseconds )

宿主定义的抽象操作 HostEnqueueTimeoutJob,接收参数 timeoutJob (a Job Abstract Closure)、realm (Realm 记录) 和 milliseconds (非负有限 Number);返回值:unused。 它安排 timeoutJob 在至少 milliseconds 毫秒后,在由 realm.[[AgentSignifier]] 所指示代理中的 Realm realm 内执行。

HostEnqueueTimeoutJob 的实现必须符合 9.5 中的要求。

9.6 代理

代理由一组 ECMAScript 执行上下文、一个执行上下文栈、一个正在运行的执行上下文、一个 Agent Record 和一个执行线程组成。除执行线程外,代理的各组成部分都专属于该代理。

一个代理的执行线程独立于其他代理,对该代理的执行上下文执行算法步骤;但一个执行线程可以由多个代理共同作为其执行线程,前提是共享该线程的代理中没有任何代理的 Agent Record 的 [[CanBlock]] 字段为 true。

注 1

例如,一些 Web 浏览器会在一个浏览器窗口的多个不相关标签页之间共享单个执行线程。

当一个代理的执行线程正在执行算法步骤时,该代理就是这些步骤的周围代理。这些步骤使用周围代理来访问该代理中保存的规范级执行对象:正在运行的执行上下文、执行上下文栈以及 Agent Record 的字段。

代理标识符是用于标识 Agent 的全局唯一不透明值。

表 25: Agent Record 字段
字段名称 值 含义
[[LittleEndian]] Boolean 当算法 GetValueFromBuffer 和 SetValueInBuffer 需要 isLittleEndian 参数时,为该参数计算的默认值。该选择由实现定义,并应选择对实现而言最高效的方案。
[[CanBlock]] Boolean 确定代理是否可以阻塞。
[[Signifier]] 代理标识符 在其代理集群中唯一标识该代理。
[[IsLockFree1]] Boolean 如果对一个字节值的原子操作是无锁的,则为 true,否则为 false。
[[IsLockFree2]] Boolean 如果对两个字节值的原子操作是无锁的,则为 true,否则为 false。
[[IsLockFree8]] Boolean 如果对八个字节值的原子操作是无锁的,则为 true,否则为 false。
[[CandidateExecution]] 候选执行 Record 参见内存模型。
[[KeptAlive]] Object 或 Symbol 的 List 初始为新的空 List,表示在当前 Job 结束之前要保持存活的对象和/或 Symbol 列表
[[ModuleAsyncEvaluationCount]] 整数 初始为 0,用于为异步模块或具有异步依赖项的模块的 [[AsyncEvaluationOrder]] 字段分配唯一且递增的值。
[[GlobalSymbolRegistry]] GlobalSymbolRegistry Record 的 List 初始为新的空 List,表示由 Symbol.for 产生的 Symbol 值列表。

[[LittleEndian]]、[[Signifier]]、[[IsLockFree1]]、[[IsLockFree2]] 和 [[IsLockFree8]] 的值不能更改。

[[GlobalSymbolRegistry]] List 只能追加,且永远不会被重新赋值。

注 2

[[IsLockFree1]]、[[IsLockFree2]] 和 [[IsLockFree8]] 的值不一定由硬件决定,也可能反映实现选择,并且这些选择可能随时间和不同 ECMAScript 实现而变化。

不存在 [[IsLockFree4]] 字段:4 字节原子操作始终是无锁的。

实际上,如果原子操作使用任何类型的锁来实现,则该操作就不是无锁的。无锁并不意味着无等待:完成一个无锁原子操作可能需要多少机器步骤不存在上限。

大小为 n 的原子访问是无锁的,并不意味着大小为 n 的非原子访问的(感知)原子性具有任何性质;具体而言,非原子访问仍然可能作为多个独立内存访问的序列执行。详见 ReadSharedMemory 和 WriteSharedMemory。

注 3

代理是一种规范机制,无需对应于 ECMAScript 实现中的任何特定产物。

9.6.1 AgentSignifier ( )

抽象操作 AgentSignifier,接收无参数;返回值:an agent signifier。 调用时执行以下步骤:

  1. 令 agentRecord 为周围代理的 Agent Record。
  2. 返回 agentRecord.[[Signifier]]。

9.6.2 AgentCanSuspend ( )

抽象操作 AgentCanSuspend,接收无参数;返回值:Boolean。 调用时执行以下步骤:

  1. 令 agentRecord 为周围代理的 Agent Record。
  2. 返回 agentRecord.[[CanBlock]]。
注

在某些环境中,允许给定代理暂停可能并不合理。例如,在 Web 浏览器环境中,可以合理地禁止文档的主事件处理线程暂停,同时仍允许 worker 的事件处理线程暂停。

9.6.3 IncrementModuleAsyncEvaluationCount ( )

抽象操作 IncrementModuleAsyncEvaluationCount,接收无参数;返回值:非负整数。 调用时执行以下步骤:

  1. 令 agentRecord 为周围代理的 Agent Record。
  2. 令 count 为 agentRecord.[[ModuleAsyncEvaluationCount]]。
  3. 将 agentRecord.[[ModuleAsyncEvaluationCount]] 设置为 count + 1。
  4. 返回 count。
注

此值仅用于跟踪待处理模块之间的相对求值顺序。当没有待处理模块时,实现可以在不可观察的情况下将 [[ModuleAsyncEvaluationCount]] 重置为 0。

9.7 代理集群

代理集群是能够通过操作共享内存进行通信的代理的极大集合。

注 1

不同代理中的程序可以通过未规定的方式共享内存。至少,SharedArrayBuffer 的后备内存可以在集群中的代理之间共享。

可能存在能够通过消息传递进行通信但不能共享内存的代理;它们永远不会位于同一个代理集群中。

每个代理恰好属于一个代理集群。

注 2

集群中的所有代理不必在某个特定时刻都处于存活状态。如果代理 A 创建了另一个代理 B,随后 A 终止,而 B 创建代理 C,那么只要 A 能够与 B 共享某些内存,并且 B 能够与 C 共享某些内存,这三个代理就位于同一个集群中。

集群中的所有代理,其各自 Agent Record 中的 [[LittleEndian]] 字段必须具有相同值。

注 3

如果代理集群中的不同代理具有不同的 [[LittleEndian]] 值,则很难使用共享内存存储多字节数据。

集群中的所有代理,其各自 Agent Record 中的 [[IsLockFree1]] 字段必须具有相同值;[[IsLockFree2]] 和 [[IsLockFree8]] 字段也同样如此。

集群中的所有代理,其各自 Agent Record 中的 [[Signifier]] 字段必须具有不同值。

嵌入环境可以在代理不知情或不配合的情况下停用(停止向前进展)或激活(恢复向前进展)一个代理。如果嵌入环境这样做,则不得让集群中的某些代理保持活动,而同一集群中的其他代理被无限期停用。

注 4

上述限制的目的是避免一个代理因为另一个代理被停用而发生死锁或饥饿。例如,假设一个 HTML shared worker 的生命周期独立于任何窗口中的文档,并且允许它与这样一个独立文档的 dedicated worker 共享内存;如果在 dedicated worker 持有锁时该文档及其 dedicated worker 被停用(例如文档被压入其窗口的历史记录),然后 shared worker 尝试获取该锁,那么 shared worker 将一直被阻塞,直到 dedicated worker 再次激活——如果它还会被激活的话。与此同时,从其他窗口尝试访问该 shared worker 的其他 worker 将发生饥饿。

此限制意味着,在嵌入环境中不属于同一暂停/唤醒集合的代理之间将无法共享内存。

嵌入环境可以在代理集群中的其他代理事先不知情或不配合的情况下终止一个代理。如果代理不是因自身或集群中另一个代理的程序操作而终止,而是由集群外部力量终止,那么嵌入环境必须选择以下两种策略之一:终止集群中的所有代理;或者提供可靠的 API,使集群中的代理能够协调,从而让集群中至少一个剩余成员能够检测到该终止,并且终止数据包含足够的信息以识别被终止的代理。

注 5

此类终止的示例包括:操作系统或用户终止在独立进程中运行的代理;当按代理进行资源计量表明某代理失控时,嵌入环境自身终止与其他代理在同一进程中运行的该代理。

以下每个规范值,以及从它们传递可达的值,都恰好属于一个代理集群。

在集群中的任何代理对任何 ECMAScript 代码进行任何求值之前,集群中所有代理的 Agent Record 的 [[CandidateExecution]] 字段都设置为初始候选执行。初始候选执行是一个空候选执行,其 [[EventsRecords]] 字段是一个 List,其中针对每个代理包含一个 Agent Events Record,该 Record 的 [[AgentSignifier]] 字段是该代理的代理标识符,而其 [[EventList]] 和 [[AgentSynchronizesWith]] 字段都是空 List。

注 6

代理集群中的所有代理在其 Agent Record 的 [[CandidateExecution]] 字段中共享相同的候选执行。候选执行是内存模型使用的一种规范机制。

注 7

代理集群是一种规范机制,无需对应于 ECMAScript 实现中的任何特定产物。

9.8 向前进展

代理取得向前进展,是指它按照本规范执行一个求值步骤。

当代理正在运行的执行上下文同步且无限期地等待外部事件时,该代理变为阻塞。只有其 Agent Record 的 [[CanBlock]] 字段为 true 的代理才能在此意义上变为阻塞。未阻塞代理是指未被阻塞的代理。

实现必须确保:

  • 每个具有专用执行线程的未阻塞代理最终都会取得向前进展
  • 在一组共享执行线程的代理中,至少有一个代理最终会取得向前进展
  • 除非通过显式提供阻塞功能的 API,否则一个代理不会导致另一个代理变为阻塞。
注

这一点与内存模型中的活性保证共同确保所有 seq-cst 写入最终都能被所有代理观察到。

9.9 WeakRef 和 FinalizationRegistry 目标的处理模型

9.9.1 目标

本规范不保证任何对象或 Symbol 一定会被垃圾回收。不再存活的对象或 Symbol 可能在很长时间后才被释放,也可能永远不会被释放。因此,本规范在描述由垃圾回收触发的行为时使用“可以”一词。

WeakRef 和 FinalizationRegistry 的语义基于在特定时间点发生的两个操作:

这两个操作(ClearKeptObjects 或 CleanupFinalizationRegistry)都不能中断同步 ECMAScript 执行。由于宿主可能会组合出较长的同步 ECMAScript 执行序列,因此本规范将 ClearKeptObjects 和 CleanupFinalizationRegistry 的调度交由宿主环境处理。

某些 ECMAScript 实现包含会在后台运行的垃圾回收器实现,包括 ECMAScript 空闲时。让宿主环境调度 CleanupFinalizationRegistry,使其可以恢复 ECMAScript 执行以运行终结器工作,而这些工作可能释放所持有的值,从而降低整体内存使用量。

9.9.2 活性

对于某个对象和/或 Symbol 集合 objSet,相对于 objSet 的假想 WeakRef 无感知执行,是这样一种执行:其被引用对象属于 objSet 的 WeakRef 的抽象操作 WeakRefDeref 始终返回 undefined。

注 1
WeakRef 无感知性与活性一起刻画了两个概念。第一,WeakRef 本身不会使其被引用对象保持存活。第二,活性中的循环并不意味着一个值是存活的。具体来说,如果确定 v 的活性依赖于确定 WeakRef 被引用对象 r 的活性,那么 r 的活性不能假定 v 是存活的,因为这将形成循环推理。
注 2
WeakRef 无感知性定义在对象或 Symbol 的集合上,而不是单个值上,以考虑循环。如果定义在单个值上,那么循环中的 WeakRef 被引用对象即使其标识仅通过循环中的其他 WeakRef 被引用对象被观察到,也会被视为存活。
注 3
通俗地说,如果包含某个对象或 Symbol 的每个集合都是存活的,我们就说该对象或 Symbol 是存活的。

在求值期间的任意时刻,如果满足以下任一条件,则对象和/或 Symbol 集合 objSet 被视为存活:

  • objSet 中的任一元素包含在任一代理的 [[KeptAlive]] List 中。
  • 存在一个相对于 objSet 的有效未来假想 WeakRef 无感知执行,并且该执行观察到 objSet 中任一值的标识。
注 4
上述第二个条件旨在刻画这样一种直觉:如果一个值的标识可以通过非 WeakRef 方式观察到,则该值是存活的。可以通过观察严格相等比较,或观察该值作为 Map 中的键使用,来观察一个值的标识。
注 5

对象或 Symbol 出现在字段、内部槽或属性中,并不意味着该值是存活的。例如,如果相关值从未传回给程序,则无法被观察到。

WeakMap 中的键、WeakSet 中的成员,以及 FinalizationRegistry Cell Record 的 [[WeakRefTarget]] 和 [[UnregisterToken]] 字段都属于这种情况。

上述定义意味着,如果 WeakMap 中的键不是存活的,则其对应值也不一定是存活的。

注 6
活性是保证引擎不得清空哪些 WeakRef 的下界。这里定义的活性是不可判定的。实际上,引擎会使用诸如可达性之类的保守近似。预计实现将具有很大的自由度。

9.9.3 执行

在任意时刻,如果对象和/或 Symbol 集合 objSet 不是存活的,则 ECMAScript 实现可以原子地执行以下步骤:

  1. 对 objSet 的每个元素 value,执行
    1. 对每个满足 ref.[[WeakRefTarget]] 是 value 的 WeakRef ref,执行
      1. 将 ref.[[WeakRefTarget]] 设置为 empty。
    2. 对每个满足 finalizationRegistry.[[Cells]] 包含一个 Record cell,且 cell.[[WeakRefTarget]] 是 value 的 FinalizationRegistry finalizationRegistry,执行
      1. 将 cell.[[WeakRefTarget]] 设置为 empty。
      2. 令 enqueueCleanup 为实现定义地从 true 或 false 中选择的一个值。
      3. 如果 enqueueCleanup 是 true,则执行 HostEnqueueFinalizationRegistryCleanupJob(finalizationRegistry)。
    3. 对每个满足 map.[[WeakMapData]] 包含一个 Record entry,且 entry.[[Key]] 是 value 的 WeakMap map,执行
      1. 将 entry.[[Key]] 设置为 empty。
      2. 将 entry.[[Value]] 设置为 empty。
    4. 对每个满足 set.[[WeakSetData]] 包含 value 的 WeakSet set,执行
      1. 将 set.[[WeakSetData]] 中值为 value 的元素替换为值为 empty 的元素。
注 1

结合活性的定义,本条款规定了实现可以针对 WeakRef 应用的优化。

可以在不观察对象标识的情况下访问该对象。允许进行诸如死变量消除,以及对其标识未被观察到的非逃逸对象属性进行标量替换等优化。因此,允许这些优化以可观察方式清空指向此类对象的 WeakRef。

另一方面,如果对象的标识可观察,并且该对象位于某个 WeakRef 的 [[WeakRefTarget]] 内部槽中,则禁止进行会以可观察方式清空该 WeakRef 的重新物化等优化。

由于调用 HostEnqueueFinalizationRegistryCleanupJob 是可选的,因此在 FinalizationRegistry 中注册的对象不一定会使该 FinalizationRegistry 保持存活。实现可以因任何原因省略 FinalizationRegistry 回调,例如 FinalizationRegistry 本身已经死亡,或者应用程序正在关闭。

注 2

实现没有义务为非存活对象或 Symbol 的极大集合清空 WeakRef。

如果实现选择一个非存活集合 objSet 并在其中清空 WeakRef,则此定义要求它同时清空 objSet 中所有值对应的 WeakRef。换句话说,如果不清空指向值 v 的其他 WeakRef 可能导致某次执行观察到 v 的值,那么实现仅清空指向 v 的一个 WeakRef 而不清空那些其他 WeakRef,是不符合规范的。

9.9.4 宿主钩子

9.9.4.1 HostEnqueueFinalizationRegistryCleanupJob ( finalizationRegistry )

宿主定义的抽象操作 HostEnqueueFinalizationRegistryCleanupJob,接收参数 finalizationRegistry (FinalizationRegistry);返回值:unused。

令 cleanupJob 为一个没有参数的新 Job Abstract Closure,它捕获 finalizationRegistry,并在被调用时执行以下步骤:

  1. 令 cleanupResult 为 Completion(CleanupFinalizationRegistry(finalizationRegistry))。
  2. 如果 cleanupResult 是突然完成,则执行任何用于报告错误的宿主定义步骤。
  3. 返回 unused。

HostEnqueueFinalizationRegistryCleanupJob 的实现会在可能的情况下安排 cleanupJob 在将来的某个时间执行。它还必须符合 9.5 中的要求。

9.10 ClearKeptObjects ( )

抽象操作 ClearKeptObjects,接收无参数;返回值:unused。 ECMAScript 实现应当在 ECMAScript 执行的同步序列完成时调用 ClearKeptObjects。 调用时执行以下步骤:

  1. 令 agentRecord 为周围代理的 Agent Record。
  2. 将 agentRecord.[[KeptAlive]] 设置为新的空 List。
  3. 返回 unused。

9.11 AddToKeptObjects ( value )

抽象操作 AddToKeptObjects,接收参数 value ((Object 或 Symbol));返回值:unused。 调用时执行以下步骤:

  1. 令 agentRecord 为周围代理的 Agent Record。
  2. 将 value 追加到 agentRecord.[[KeptAlive]]。
  3. 返回 unused。
注
当使用目标对象或 Symbol 调用抽象操作 AddToKeptObjects 时,它会将目标添加到一个列表中,该列表会在调用 ClearKeptObjects 之前对目标保持强引用。

9.12 CleanupFinalizationRegistry ( finalizationRegistry )

抽象操作 CleanupFinalizationRegistry,接收参数 finalizationRegistry (FinalizationRegistry);返回值:(正常完成 (值:unused) 或 抛出完成)。 调用时执行以下步骤:

  1. 断言:finalizationRegistry 具有 [[Cells]] 和 [[CleanupCallback]] 内部槽。
  2. 令 callback 为 finalizationRegistry.[[CleanupCallback]]。
  3. 当 finalizationRegistry.[[Cells]] 包含一个 Record cell,使得 cell.[[WeakRefTarget]] 是 empty 时,实现可以执行以下步骤:
    1. 选择任意这样的 cell。
    2. 从 finalizationRegistry.[[Cells]] 中移除 cell。
    3. 执行 ? HostCallJobCallback(callback, undefined, « cell.[[HeldValue]] »)。
  4. 返回 unused。

9.13 CanBeHeldWeakly ( arg )

抽象操作 CanBeHeldWeakly,接收参数 arg (ECMAScript 语言值);返回值:Boolean。 当且仅当 arg 适合用作弱引用时,它返回 true。只有适合用作弱引用的值才能作为 WeakMap 的键、WeakSet 的元素、WeakRef 的目标,或 FinalizationRegistry 的目标之一。 调用时执行以下步骤:

  1. 如果 arg 是 Object,则返回 true。
  2. 如果 arg 是 Symbol 且 KeyForSymbol(arg) 是 undefined,则返回 true。
  3. 返回 false。
注

没有语言标识的语言值可以在没有先前引用的情况下显现,因此不适合用作弱引用。由 Symbol.for 产生的 Symbol 值与其他 Symbol 值不同,它没有语言标识,因此不适合用作弱引用。知名 Symbol 很可能永远不会被回收,但仍被视为适合用作弱引用,因为其数量有限,因此可由各种实现方式管理。不过,在存活的 WeakMap 中与知名 Symbol 关联的任何值都很可能不会被回收,并可能在实现中“泄漏”内存资源。