9 可执行代码与执行上下文 (Executable Code and Execution Contexts)

9.1 环境记录 (Environment Records)

Environment Record 是一种规范类型,用于基于 ECMAScript 代码的词法嵌套结构,将 Identifier 与特定变量及函数建立关联。通常一个 Environment Record 与某个特定的 ECMAScript 语法结构关联,如 FunctionDeclarationBlockStatementTryStatementCatch 子句。每当这类代码被求值时,就会新建一个 Environment Record,用来记录该代码创建的标识符绑定。

每个 Environment Record 都有一个 [[OuterEnv]] 字段,其值为 null 或指向一个外层 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 类型层次 (The Environment Record Type Hierarchy)

可以将 Environment Record 看作是一个简单的面向对象层次结构:Environment Record 是一个抽象类,具有三个具体子类:Declarative Environment RecordObject Environment RecordGlobal Environment RecordFunction Environment RecordModule Environment RecordDeclarative Environment Record 的子类。

Environment Record 抽象类包含 Table 14 中定义的抽象规范方法。这些抽象方法在各具体子类上有不同的具体算法。

Table 14: Environment Record 的抽象方法
方法 目的
HasBinding(N) 判断 Environment Record 是否存在字符串值 N 的绑定;存在返回 true,否则返回 false
CreateMutableBinding(N, D) 创建一个新的、未初始化的可变绑定。字符串 N 为名称文本。若布尔参数 Dtrue,该绑定之后可删除。
CreateImmutableBinding(N, S) 创建新的、未初始化的不可变绑定。字符串 N 为名称文本。若 Strue,初始化后再设置将始终抛出异常(与引用该绑定的操作是否严格模式无关)。
InitializeBinding(N, V) 为已存在但未初始化的绑定设置值。N 为名称文本,V 为任意 ECMAScript 语言类型的值。
SetMutableBinding(N, V, S) 为已存在的可变绑定设置值 VS 为布尔标记;若 Strue 且绑定无法被设置则抛出 TypeError
GetBindingValue(N, S) 返回已存在绑定的值。S 标记引用是否源自严格模式(或需要严格语义)。若 Strue 且绑定不存在抛 ReferenceError。若绑定存在但未初始化,无论 S 值为何都抛 ReferenceError
DeleteBinding(N) 删除名称为 N 的绑定。存在则移除并返回 true;存在但不可移除返回 false;不存在返回 true
HasThisBinding() 判断是否建立 this 绑定;是返回 true,否则 false
HasSuperBinding() 判断是否建立 super 方法绑定;是返回 true,否则 false。若返回 true 则表明该记录是 Function Environment Record(反之不一定)。
WithBaseObject() 若该 Environment Recordwith 语句关联则返回其对象;否则返回 undefined

9.1.1.1 声明式环境记录 (Declarative Environment Records)

每个 Declarative Environment Record 与一个 ECMAScript 程序作用域关联,该作用域包含变量、常量、let、class、module、import 以及(或)函数声明。Declarative Environment Record 绑定其作用域内声明定义的标识符集合。

9.1.1.1.1 HasBinding ( N )

The HasBinding concrete method of takes argument N (一个 String) and returns 一个包含 Boolean 的正常完成. It performs the following steps when called:

  1. envRecN 有绑定,返回 true
  2. 返回 false

9.1.1.1.2 CreateMutableBinding ( N, D )

The CreateMutableBinding concrete method of takes arguments N (一个 String) and D (一个 Boolean) and returns 一个包含 unused正常完成. It performs the following steps when called:

  1. 断言:envRec 尚无 N 绑定。
  2. envRec 中创建 N 的可变绑定并记录其未初始化。若 Dtrue,记录该绑定可被后续 DeleteBinding 删除。
  3. 返回 unused

9.1.1.1.3 CreateImmutableBinding ( N, S )

The CreateImmutableBinding concrete method of takes arguments N (一个 String) and S (一个 Boolean) and returns 一个包含 unused正常完成. It performs the following steps when called:

  1. 断言:envRec 尚无 N 绑定。
  2. envRec 中创建 N 的不可变绑定并记录其未初始化。若 Strue,记录其为严格绑定。
  3. 返回 unused

9.1.1.1.4 InitializeBinding ( N, V )

The InitializeBinding concrete method of takes arguments N (一个 String) and V (一个 ECMAScript 语言值) and returns 一个包含 unused正常完成. It performs the following steps when called:

  1. 断言:envRec 必须有 N 的未初始化绑定。
  2. envRecN 的绑定值设为 V
  3. 记录 envRecN 的绑定已被初始化。
  4. 返回 unused

9.1.1.1.5 SetMutableBinding ( N, V, S )

The SetMutableBinding concrete method of takes arguments N (一个 String), V (一个 ECMAScript 语言值), and S (一个 Boolean) and returns 一个包含 unused正常完成或一个抛出完成. It performs the following steps when called:

  1. envRecN 绑定,则
    1. Strue,抛 ReferenceError
    2. 执行 ! envRec.CreateMutableBinding(N, true)。
    3. 执行 ! envRec.InitializeBinding(N, V)。
    4. 返回 unused
  2. envRecN 的绑定是严格绑定,将 S 设为 true
  3. envRecN 的绑定尚未初始化,则
    1. ReferenceError
  4. 否则若为可变绑定,
    1. 将其值改为 V
  5. 否则,
    1. 断言:正在尝试修改不可变绑定的值。
    2. Strue,抛 TypeError
  6. 返回 unused
Note

导致在步骤 1 出现缺失绑定的 ECMAScript 示例:

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

9.1.1.1.6 GetBindingValue ( N, S )

The GetBindingValue concrete method of takes arguments N (一个 String) and S (一个 Boolean) and returns 一个包含 ECMAScript 语言值正常完成或一个抛出完成. It performs the following steps when called:

  1. 断言:envRecN 的绑定。
  2. 若其为未初始化绑定,抛 ReferenceError
  3. 返回当前绑定于 N 的值。

9.1.1.1.7 DeleteBinding ( N )

The DeleteBinding concrete method of takes argument N (一个 String) and returns 一个包含 Boolean 的正常完成. It performs the following steps when called:

  1. 断言:envRecN 的绑定。
  2. 若该绑定不可删除,返回 false
  3. envRec 移除该绑定。
  4. 返回 true

9.1.1.1.8 HasThisBinding ( )

The HasThisBinding concrete method of takes no arguments and returns false. It performs the following steps when called:

  1. 返回 false
Note

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

9.1.1.1.9 HasSuperBinding ( )

The HasSuperBinding concrete method of takes no arguments and returns false. It performs the following steps when called:

  1. 返回 false
Note

普通 Declarative Environment Record 不提供 super 绑定。

9.1.1.1.10 WithBaseObject ( )

The WithBaseObject concrete method of takes no arguments and returns undefined. It performs the following steps when called:

  1. 返回 undefined

9.1.1.2 对象环境记录 (Object Environment Records)

每个 Object Environment Record 关联一个称为其 binding object 的对象。它绑定该对象属性名中与字符串标识符名称直接对应的集合。不是 IdentifierName 形式字符串的属性键不计入。集合包含自有与继承属性,与其 [[Enumerable]] 属性设置无关。由于对象属性可动态添加/删除,对应绑定集合可能随任何添加或删除属性的操作产生副作用而变化。副作用新增的绑定被视为可变绑定,即使对应属性的 Writable 为 false。Object Environment Record 不存在不可变绑定。

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

Object Environment Record 具有 Table 15 所列附加状态字段。

Table 15: Object Environment Record 的附加字段
字段名 含义
[[BindingObject]] 一个 Object Environment Record 的绑定对象。
[[IsWithEnvironment]] 一个 Boolean 指示该记录是否为 with 语句创建。

9.1.1.2.1 HasBinding ( N )

The HasBinding concrete method of takes argument N (一个 String) and returns 一个包含 Boolean 的正常完成或抛出完成. It performs the following steps when called:

  1. bindingObjectenvRec.[[BindingObject]]
  2. foundBinding 为 ? HasProperty(bindingObject, N)。
  3. foundBindingfalse,返回 false
  4. envRec.[[IsWithEnvironment]]false,返回 true
  5. unscopables 为 ? Get(bindingObject, %Symbol.unscopables%)。
  6. unscopables 是 Object,则
    1. blockedToBoolean(? Get(unscopables, N))。
    2. blockedtrue,返回 false
  7. 返回 true

9.1.1.2.2 CreateMutableBinding ( N, D )

The CreateMutableBinding concrete method of takes arguments N (一个 String) and D (一个 Boolean) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. bindingObjectenvRec.[[BindingObject]]
  2. 执行 ? DefinePropertyOrThrow(bindingObject, N, PropertyDescriptor { [[Value]]: undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D })。
  3. 返回 unused
Note

通常 envRec 不会已有 N 绑定;若已存在,DefinePropertyOrThrow 的语义可能替换、遮蔽或抛出异常。

9.1.1.2.3 CreateImmutableBinding ( N, S )

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

9.1.1.2.4 InitializeBinding ( N, V )

The InitializeBinding concrete method of takes arguments N (一个 String) and V (一个 ECMAScript 语言值) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. 执行 ? envRec.SetMutableBinding(N, V, false)。
  2. 返回 unused
Note

在本规范中,对 Object Environment Record 调用 CreateMutableBinding 后立即调用 InitializeBinding,因此不显式跟踪其初始化状态。

9.1.1.2.5 SetMutableBinding ( N, V, S )

The SetMutableBinding concrete method of takes arguments N (一个 String), V (一个 ECMAScript 语言值), and S (一个 Boolean) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. bindingObjectenvRec.[[BindingObject]]
  2. stillExists 为 ? HasProperty(bindingObject, N)。
  3. stillExistsfalseStrue,抛 ReferenceError
  4. 执行 ? Set(bindingObject, N, V, S)。
  5. 返回 unused

9.1.1.2.6 GetBindingValue ( N, S )

The GetBindingValue concrete method of takes arguments N (一个 String) and S (一个 Boolean) and returns 一个包含 ECMAScript 语言值正常完成或抛出完成. It performs the following steps when called:

  1. bindingObjectenvRec.[[BindingObject]]
  2. value 为 ? HasProperty(bindingObject, N)。
  3. valuefalse,则
    1. Sfalse,返回 undefined;否则抛 ReferenceError
  4. 返回 ? Get(bindingObject, N)。

9.1.1.2.7 DeleteBinding ( N )

The DeleteBinding concrete method of takes argument N (一个 String) and returns 一个包含 Boolean 的正常完成或抛出完成. It performs the following steps when called:

  1. bindingObjectenvRec.[[BindingObject]]
  2. 返回 ? bindingObject.[[Delete]](N)。

9.1.1.2.8 HasThisBinding ( )

The HasThisBinding concrete method of takes no arguments and returns false. It performs the following steps when called:

  1. 返回 false
Note

Object Environment Record 不提供 this 绑定。

9.1.1.2.9 HasSuperBinding ( )

The HasSuperBinding concrete method of takes no arguments and returns false. It performs the following steps when called:

  1. 返回 false
Note

Object Environment Record 不提供 super 绑定。

9.1.1.2.10 WithBaseObject ( )

The WithBaseObject concrete method of takes no arguments and returns 一个 Object 或 undefined. It performs the following steps when called:

  1. envRec.[[IsWithEnvironment]]true,返回 envRec.[[BindingObject]]
  2. 否则返回 undefined

9.1.1.3 函数环境记录 (Function Environment Records)

Function Environment Record 是一个 Declarative Environment Record,表示函数的顶层作用域,并且若函数不是 ArrowFunction,则提供 this 绑定。若一个非 ArrowFunction 函数引用 super,其 Function Environment Record 也包含执行 super 方法调用所需的状态。

Function Environment Record 有 Table 16 中列出的附加状态字段。

Table 16: Function Environment Record 的附加字段
字段名 含义
[[ThisValue]] 一个 ECMAScript 语言值 此次函数调用使用的 this 值。
[[ThisBindingStatus]] lexical, initialized, 或 uninitialized 若为 lexical,表明是 ArrowFunction,无本地 this
[[FunctionObject]] 一个 ECMAScript 函数对象 其调用导致此 Environment Record 被创建的函数对象
[[NewTarget]] 一个 constructor 或 undefined 若由 [[Construct]] 创建,则为该内部方法 newTarget 参数;否则为 undefined

Function Environment Record 支持 Table 14 中列出的所有 Declarative Environment Record 方法,除 HasThisBinding 与 HasSuperBinding 外与其规范相同;另外支持 Table 17 中列出的方法:

Table 17: Function Environment Record 的附加方法
方法 目的
GetThisBinding() 返回该 Environment Recordthis 绑定值,若尚未初始化则抛 ReferenceError

9.1.1.3.1 BindThisValue ( envRec, V )

The abstract operation BindThisValue takes arguments envRec (一个 Function Environment Record) and V (一个 ECMAScript 语言值) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. 断言:envRec.[[ThisBindingStatus]] 不为 lexical
  2. envRec.[[ThisBindingStatus]]initialized,抛 ReferenceError
  3. envRec.[[ThisValue]]V
  4. envRec.[[ThisBindingStatus]]initialized
  5. 返回 unused

9.1.1.3.2 HasThisBinding ( )

The HasThisBinding concrete method of takes no arguments and returns 一个 Boolean. It performs the following steps when called:

  1. envRec.[[ThisBindingStatus]]lexical,返回 false;否则返回 true

9.1.1.3.3 HasSuperBinding ( )

The HasSuperBinding concrete method of takes no arguments and returns 一个 Boolean. It performs the following steps when called:

  1. envRec.[[ThisBindingStatus]]lexical,返回 false
  2. envRec.[[FunctionObject]].[[HomeObject]]undefined,返回 false;否则返回 true

9.1.1.3.4 GetThisBinding ( )

The GetThisBinding concrete method of takes no arguments and returns 一个包含 ECMAScript 语言值正常完成或抛出完成. It performs the following steps when called:

  1. 断言:envRec.[[ThisBindingStatus]] 不为 lexical
  2. envRec.[[ThisBindingStatus]]uninitialized,抛 ReferenceError
  3. 返回 envRec.[[ThisValue]]

9.1.1.3.5 GetSuperBase ( envRec )

The abstract operation GetSuperBase takes argument envRec (一个 Function Environment Record) and returns 一个 Object、nullundefined. It performs the following steps when called:

  1. homeenvRec.[[FunctionObject]].[[HomeObject]]
  2. homeundefined,返回 undefined
  3. 断言:home普通对象
  4. 返回 ! home.[[GetPrototypeOf]]()。

9.1.1.4 全局环境记录 (Global Environment Records)

Global Environment Record 表示在同一 realm 中处理的所有 ECMAScript Script 元素共享的最外层作用域。提供内置全局(19)、全局对象属性以及所有顶层声明(8.2.98.2.11)的绑定。

Global Environment Record 在逻辑上是单一记录,但被描述为封装一个 Object Environment Record 和一个 Declarative Environment Record 的复合体。Object Environment Record 的基对象为关联 Realm Record 的全局对象。该全局对象是其 GetThisBinding 具体方法返回的值。Object 组件包含内置全局与由 FunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclarationVariableStatement 引入的全局代码绑定;其余声明的绑定位于 Declarative 组件。

可以直接在全局对象上创建属性,因此 Object 组件可能同时包含通过声明显式创建的绑定与作为全局对象属性隐式创建的绑定。为区分通过声明显式创建的绑定,Global Environment Record 维护使用 CreateGlobalVarBindingCreateGlobalFunctionBinding 创建的名称列表。

Global Environment Record 具有 Table 18 中的附加字段和 Table 19 中的附加方法。

Table 18: Global Environment Record 的附加字段
字段名 含义
[[ObjectRecord]] 一个 Object Environment Record 绑定对象是全局对象,包含全局内置绑定以及全局代码中 FunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclarationVariableDeclaration 的绑定。
[[GlobalThisValue]] 一个 Object 全局作用域中 this 返回的值;宿主可提供任意 ECMAScript Object。
[[DeclarativeRecord]] 一个 Declarative Environment Record 包含 全局代码中除 FunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclarationVariableDeclaration 外所有声明的绑定。
Table 19: Global Environment Record 的附加方法
方法 目的
GetThisBinding() 返回该 Environment Recordthis 绑定。

9.1.1.4.1 HasBinding ( N )

The HasBinding concrete method of takes argument N (一个 String) and returns 一个包含 Boolean 的正常完成或抛出完成. It performs the following steps when called:

  1. DclRecenvRec.[[DeclarativeRecord]]
  2. 若 ! DclRec.HasBinding(N) 为 true,返回 true
  3. ObjRecenvRec.[[ObjectRecord]]
  4. 返回 ? ObjRec.HasBinding(N)。

9.1.1.4.2 CreateMutableBinding ( N, D )

The CreateMutableBinding concrete method of takes arguments N (一个 String) and D (一个 Boolean) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. DclRecenvRec.[[DeclarativeRecord]]
  2. 若 ! DclRec.HasBinding(N) 为 true,抛 TypeError
  3. 返回 ! DclRec.CreateMutableBinding(N, D)。

9.1.1.4.3 CreateImmutableBinding ( N, S )

The CreateImmutableBinding concrete method of takes arguments N (一个 String) and S (一个 Boolean) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. DclRecenvRec.[[DeclarativeRecord]]
  2. 若 ! DclRec.HasBinding(N) 为 true,抛 TypeError
  3. 返回 ! DclRec.CreateImmutableBinding(N, S)。

9.1.1.4.4 InitializeBinding ( N, V )

The InitializeBinding concrete method of takes arguments N (一个 String) and V (一个 ECMAScript 语言值) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. DclRecenvRec.[[DeclarativeRecord]]
  2. 若 ! DclRec.HasBinding(N) 为 true,则
    1. 返回 ! DclRec.InitializeBinding(N, V)。
  3. 断言:若存在绑定则位于 Object Environment Record 中。
  4. ObjRecenvRec.[[ObjectRecord]]
  5. 返回 ? ObjRec.InitializeBinding(N, V)。

9.1.1.4.5 SetMutableBinding ( N, V, S )

The SetMutableBinding concrete method of takes arguments N (一个 String), V (一个 ECMAScript 语言值), and S (一个 Boolean) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. DclRecenvRec.[[DeclarativeRecord]]
  2. 若 ! DclRec.HasBinding(N) 为 true,则
    1. 返回 ? DclRec.SetMutableBinding(N, V, S)。
  3. ObjRecenvRec.[[ObjectRecord]]
  4. 返回 ? ObjRec.SetMutableBinding(N, V, S)。

9.1.1.4.6 GetBindingValue ( N, S )

The GetBindingValue concrete method of takes arguments N (一个 String) and S (一个 Boolean) and returns 一个包含 ECMAScript 语言值正常完成或抛出完成. It performs the following steps when called:

  1. DclRecenvRec.[[DeclarativeRecord]]
  2. 若 ! DclRec.HasBinding(N) 为 true,则
    1. 返回 ? DclRec.GetBindingValue(N, S)。
  3. ObjRecenvRec.[[ObjectRecord]]
  4. 返回 ? ObjRec.GetBindingValue(N, S)。

9.1.1.4.7 DeleteBinding ( N )

The DeleteBinding concrete method of takes argument N (一个 String) and returns 一个包含 Boolean 的正常完成或抛出完成. It performs the following steps when called:

  1. DclRecenvRec.[[DeclarativeRecord]]
  2. 若 ! DclRec.HasBinding(N) 为 true,则
    1. 返回 ! DclRec.DeleteBinding(N)。
  3. ObjRecenvRec.[[ObjectRecord]]
  4. globalObjectObjRec.[[BindingObject]]
  5. existingProp 为 ? HasOwnProperty(globalObject, N)。
  6. existingProptrue,则
    1. 返回 ? ObjRec.DeleteBinding(N)。
  7. 返回 true

9.1.1.4.8 HasThisBinding ( )

The HasThisBinding concrete method of takes no arguments and returns true. It performs the following steps when called:

  1. 返回 true
Note

Global Environment Record 始终提供 this 绑定。

9.1.1.4.9 HasSuperBinding ( )

The HasSuperBinding concrete method of takes no arguments and returns false. It performs the following steps when called:

  1. 返回 false
Note

Global Environment Record 不提供 super 绑定。

9.1.1.4.10 WithBaseObject ( )

The WithBaseObject concrete method of takes no arguments and returns undefined. It performs the following steps when called:

  1. 返回 undefined

9.1.1.4.11 GetThisBinding ( )

The GetThisBinding concrete method of takes no arguments and returns 一个包含 Object 的正常完成. It performs the following steps when called:

  1. 返回 envRec.[[GlobalThisValue]]

9.1.1.4.12 HasLexicalDeclaration ( envRec, N )

The abstract operation HasLexicalDeclaration takes arguments envRec (一个 Global Environment Record) and N (一个 String) and returns 一个 Boolean. It performs the following steps when called:

  1. DclRecenvRec.[[DeclarativeRecord]]
  2. 返回 ! DclRec.HasBinding(N)。

9.1.1.4.13 HasRestrictedGlobalProperty ( envRec, N )

The abstract operation HasRestrictedGlobalProperty takes arguments envRec (一个 Global Environment Record) and N (一个 String) and returns 一个包含 Boolean 的正常完成或抛出完成. It performs the following steps when called:

  1. ObjRecenvRec.[[ObjectRecord]]
  2. globalObjectObjRec.[[BindingObject]]
  3. existingProp 为 ? globalObject.[[GetOwnProperty]](N)。
  4. existingPropundefined,返回 false
  5. existingProp.[[Configurable]]true,返回 false
  6. 返回 true
Note

可直接在全局对象上存在非声明创建的属性。不能创建与全局对象不可配置属性同名的全局词法绑定,例如 "undefined"

9.1.1.4.14 CanDeclareGlobalVar ( envRec, N )

The abstract operation CanDeclareGlobalVar takes arguments envRec (一个 Global Environment Record) and N (一个 String) and returns 一个包含 Boolean 的正常完成或抛出完成. It performs the following steps when called:

  1. ObjRecenvRec.[[ObjectRecord]]
  2. globalObjectObjRec.[[BindingObject]]
  3. hasProperty 为 ? HasOwnProperty(globalObject, N)。
  4. hasPropertytrue,返回 true
  5. 返回 ? IsExtensible(globalObject)。

9.1.1.4.15 CanDeclareGlobalFunction ( envRec, N )

The abstract operation CanDeclareGlobalFunction takes arguments envRec (一个 Global Environment Record) and N (一个 String) and returns 一个包含 Boolean 的正常完成或抛出完成. It performs the following steps when called:

  1. ObjRecenvRec.[[ObjectRecord]]
  2. globalObjectObjRec.[[BindingObject]]
  3. existingProp 为 ? globalObject.[[GetOwnProperty]](N)。
  4. existingPropundefined,返回 ? IsExtensible(globalObject)。
  5. existingProp.[[Configurable]]true,返回 true
  6. IsDataDescriptor(existingProp) 为 trueexistingProp 具属性 { [[Writable]]: true, [[Enumerable]]: true },返回 true
  7. 返回 false

9.1.1.4.16 CreateGlobalVarBinding ( envRec, N, D )

The abstract operation CreateGlobalVarBinding takes arguments envRec (一个 Global Environment Record), N (一个 String), and D (一个 Boolean) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. ObjRecenvRec.[[ObjectRecord]]
  2. globalObjectObjRec.[[BindingObject]]
  3. hasProperty 为 ? HasOwnProperty(globalObject, N)。
  4. extensible 为 ? IsExtensible(globalObject)。
  5. hasPropertyfalseextensibletrue,则
    1. 执行 ? ObjRec.CreateMutableBinding(N, D)。
    2. 执行 ? ObjRec.InitializeBinding(N, undefined)。
  6. 返回 unused

9.1.1.4.17 CreateGlobalFunctionBinding ( envRec, N, V, D )

The abstract operation CreateGlobalFunctionBinding takes arguments envRec (一个 Global Environment Record), N (一个 String), V (一个 ECMAScript 语言值), and D (一个 Boolean) and returns 一个包含 unused正常完成或抛出完成. It performs the following steps when called:

  1. ObjRecenvRec.[[ObjectRecord]]
  2. globalObjectObjRec.[[BindingObject]]
  3. existingProp 为 ? globalObject.[[GetOwnProperty]](N)。
  4. existingPropundefined 或其 [[Configurable]]true,则
    1. desc 为 PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D }。
  5. 否则,
    1. desc 为 PropertyDescriptor { [[Value]]: V }。
  6. 执行 ? DefinePropertyOrThrow(globalObject, N, desc)。
  7. 执行 ? Set(globalObject, N, V, false)。
  8. 返回 unused
Note

全局函数声明总以全局对象自有属性表示;若可行,重配置为标准属性集。步骤 7 等价于调用 InitializeBinding,且若 globalObject 为 Proxy 将产生相同的 trap 调用序列。

9.1.1.5 模块环境记录 (Module Environment Records)

Module Environment Record 是一个 Declarative Environment Record,用于表示 ECMAScript Module 的外层作用域。除普通可变与不可变绑定外,还提供不可变的 import 绑定,这些绑定间接访问另一个 Environment Record 中的目标绑定。

Module Environment Record 支持 Table 14 中列出的所有 Declarative Environment Record 方法,除 GetBindingValue、DeleteBinding、HasThisBinding 与 GetThisBinding 外与其规范相同;另外支持 Table 20 中的方法:

Table 20: Module Environment Record 的附加方法
方法 目的
GetThisBinding() 返回该 Environment Recordthis 绑定值。

9.1.1.5.1 GetBindingValue ( N, S )

The GetBindingValue concrete method of takes arguments N (一个 String) and S (一个 Boolean) and returns 一个包含 ECMAScript 语言值正常完成或抛出完成. It performs the following steps when called:

  1. 断言:Strue
  2. 断言:envRecN 绑定。
  3. N 的绑定是间接绑定,则
    1. MN2 为创建该绑定时提供的间接值。
    2. targetEnvM.[[Environment]]
    3. targetEnvempty,抛 ReferenceError
    4. 返回 ? targetEnv.GetBindingValue(N2, true)。
  4. envRecN 的绑定为未初始化,抛 ReferenceError
  5. 返回当前绑定于 N 的值。
Note

S 始终为 true,因为 Module 总是严格模式。

9.1.1.5.2 DeleteBinding ( N )

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

Note

Module Environment Record 仅用于严格代码,并且早期错误规则阻止在严格代码中对解析到模块环境绑定的 Reference Record 使用 delete。见 13.5.1.1

9.1.1.5.3 HasThisBinding ( )

The HasThisBinding concrete method of takes no arguments and returns true. It performs the following steps when called:

  1. 返回 true
Note

Module Environment Record 始终提供 this 绑定。

9.1.1.5.4 GetThisBinding ( )

The GetThisBinding concrete method of takes no arguments and returns 一个包含 undefined正常完成. It performs the following steps when called:

  1. 返回 undefined

9.1.1.5.5 CreateImportBinding ( envRec, N, M, N2 )

The abstract operation CreateImportBinding takes arguments envRec (一个 Module Environment Record), N (一个 String), M (一个 Module Record), and N2 (一个 String) and returns unused. It performs the following steps when called:

  1. 断言:envRec 尚无 N 绑定。
  2. 断言:当 M.[[Environment]] 实例化时会有 N2 的直接绑定。
  3. envRec 中创建引用 MN2 的不可变间接绑定并记录其已初始化。
  4. 返回 unused

9.1.2 环境记录操作 (Environment Record Operations)

下列抽象操作用于在本规范中对 Environment Record 进行操作:

9.1.2.1 GetIdentifierReference ( env, name, strict )

The abstract operation GetIdentifierReference takes arguments env (一个 Environment Recordnull), name (一个 String), and strict (一个 Boolean) and returns 一个包含 Reference Record正常完成或抛出完成. It performs the following steps when called:

  1. envnull,则
    1. 返回 Reference Record { [[Base]]: unresolvable, [[ReferencedName]]: name, [[Strict]]: strict, [[ThisValue]]: empty }。
  2. exists 为 ? env.HasBinding(name)。
  3. existstrue,则
    1. 返回 Reference Record { [[Base]]: env, [[ReferencedName]]: name, [[Strict]]: strict, [[ThisValue]]: empty }。
  4. 否则,
    1. outerenv.[[OuterEnv]]
    2. 返回 ? GetIdentifierReference(outer, name, strict)。

9.1.2.2 NewDeclarativeEnvironment ( E )

The abstract operation NewDeclarativeEnvironment takes argument E (一个 Environment Recordnull) and returns 一个 Declarative Environment Record. It performs the following steps when called:

  1. env 为一个不含绑定的新 Declarative Environment Record
  2. env.[[OuterEnv]]E
  3. 返回 env

9.1.2.3 NewObjectEnvironment ( O, W, E )

The abstract operation NewObjectEnvironment takes arguments O (一个 Object), W (一个 Boolean), and E (一个 Environment Recordnull) and returns 一个 Object Environment Record. It performs the following steps when called:

  1. env 为一个新 Object Environment Record
  2. env.[[BindingObject]]O
  3. env.[[IsWithEnvironment]]W
  4. env.[[OuterEnv]]E
  5. 返回 env

9.1.2.4 NewFunctionEnvironment ( F, newTarget )

The abstract operation NewFunctionEnvironment takes arguments F (一个 ECMAScript 函数对象) and newTarget (一个 Object 或 undefined) and returns 一个 Function Environment Record. It performs the following steps when called:

  1. env 为一个不含绑定的新 Function Environment Record
  2. env.[[FunctionObject]]F
  3. F.[[ThisMode]]lexical,设 env.[[ThisBindingStatus]]lexical
  4. 否则设 env.[[ThisBindingStatus]]uninitialized
  5. env.[[NewTarget]]newTarget
  6. env.[[OuterEnv]]F.[[Environment]]
  7. 返回 env

9.1.2.5 NewGlobalEnvironment ( G, thisValue )

The abstract operation NewGlobalEnvironment takes arguments G (一个 Object) and thisValue (一个 Object) and returns 一个 Global Environment Record. It performs the following steps when called:

  1. objRecNewObjectEnvironment(G, false, null)。
  2. dclRecNewDeclarativeEnvironment(null)。
  3. env 为一个新 Global Environment Record
  4. env.[[ObjectRecord]]objRec
  5. env.[[GlobalThisValue]]thisValue
  6. env.[[DeclarativeRecord]]dclRec
  7. env.[[OuterEnv]]null
  8. 返回 env

9.1.2.6 NewModuleEnvironment ( E )

The abstract operation NewModuleEnvironment takes argument E (一个 Environment Record) and returns 一个 Module Environment Record. It performs the following steps when called:

  1. env 为一个不含绑定的新 Module Environment Record
  2. env.[[OuterEnv]]E
  3. 返回 env

9.2 PrivateEnvironment 记录 (PrivateEnvironment Records)

PrivateEnvironment Record 是一种规范机制,用于基于 ECMAScript 代码中 ClassDeclarationClassExpression 的词法嵌套结构跟踪 Private Name。它们与 Environment Record 类似但不同。每个 PrivateEnvironment Record 与一个 ClassDeclarationClassExpression 关联。每次此类 class 被求值时,会创建一个新的 PrivateEnvironment Record 来记录该 class 声明的 Private Name

每个 PrivateEnvironment Record 拥有 Table 21 中定义的字段。

Table 21: PrivateEnvironment Record 字段
字段名 值类型 含义
[[OuterPrivateEnvironment]] 一个 PrivateEnvironment Recordnull 最近包围的 class 的 PrivateEnvironment Record。若与此 PrivateEnvironment Record 关联的 class 未被任何其他 class 包含则为 null
[[Names]] 一个 Private Name 列表 该 class 声明的 Private Name

9.2.1 PrivateEnvironment Record 操作 (PrivateEnvironment Record Operations)

以下抽象操作用于在本规范中对 PrivateEnvironment Record 进行操作:

9.2.1.1 NewPrivateEnvironment ( outerPrivateEnv )

The abstract operation NewPrivateEnvironment takes argument outerPrivateEnv (a PrivateEnvironment Record or null) and returns a PrivateEnvironment Record. It performs the following steps when called:

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

9.2.1.2 ResolvePrivateIdentifier ( privateEnv, identifier )

The abstract operation ResolvePrivateIdentifier takes arguments privateEnv (a PrivateEnvironment Record) and identifier (a String) and returns a Private Name. It performs the following steps when called:

  1. namesprivateEnv.[[Names]]
  2. 对于 names 中每个 Private Name pn,执行
    1. pn.[[Description]]identifier,则
      1. 返回 pn
  3. outerPrivateEnvprivateEnv.[[OuterPrivateEnvironment]]
  4. 断言:outerPrivateEnv 不为 null
  5. 返回 ResolvePrivateIdentifier(outerPrivateEnv, identifier)。

9.3 Realm

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

在本规范中,一个 realm 表示为具有 Table 22 中字段的 Realm Record

Table 22: Realm Record 字段
字段名 含义
[[AgentSignifier]] 一个 agent 标识符 拥有该 realm 的 agent
[[Intrinsics]] 一个 Record,其字段名为内在 key,值为对象 与该 realm 关联的代码使用的内在值
[[GlobalObject]] 一个 Object realm 的全局对象
[[GlobalEnv]] 一个 Global Environment Record realm 的全局环境
[[TemplateMap]] 一个 Record 列表,字段 [[Site]] (一个 TemplateLiteral Parse Node) 与 [[Array]] (一个 Array)

模板对象按 realm 独立规范化,使用其 Realm Record[[TemplateMap]]。每个 [[Site]] 值是一个 TemplateLiteral Parse Node。其关联的 [[Array]] 是传递给 tag 函数的对应模板对象。

Note 1
一旦某 Parse Node 变为不可达,对应 [[Array]] 也不可达;实现移除该对条目将不可观察。
[[LoadedModules]] 一个 LoadedModuleRequest Record 列表

从该 realm 导入的 specifier 字符串到解析后 Module Record 的映射。该列表不包含两个不同 Record r1r2 使得 ModuleRequestsEqual(r1, r2) 为 true

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

9.3.1 InitializeHostDefinedRealm ( )

The abstract operation InitializeHostDefinedRealm takes no arguments and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

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

9.3.2 CreateIntrinsics ( realmRec )

The abstract operation CreateIntrinsics takes argument realmRec (a Realm Record) and returns unused. It performs the following steps when called:

  1. realmRec.[[Intrinsics]] 设为一个新的 Record
  2. Table 6 中的值设置 realmRec.[[Intrinsics]] 的字段。字段名为该表第一列列出的名称。每个字段的值为一个根据 1928 中各对象规范完全递归填充属性值的新对象。所有对象属性值均为新创建对象。所有内置函数对象通过执行 CreateBuiltinFunction(steps, length, name, slots, realmRec, prototype) 创建,其中 steps 是本规范给出的该函数定义,name 是函数 "name" 属性初始值,length 是函数 "length" 属性初始值,slots 是函数指定内部槽名称列表(若有),prototype 是指定的 [[Prototype]] 内部槽值。内在对象及其属性的创建顺序必须避免依赖尚未创建的对象。
  3. 执行 AddRestrictedFunctionProperties(realmRec.[[Intrinsics]].[[%Function.prototype%]], realmRec)。
  4. 返回 unused

9.3.3 SetDefaultGlobalBindings ( realmRec )

The abstract operation SetDefaultGlobalBindings takes argument realmRec (a Realm Record) and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. globalrealmRec.[[GlobalObject]]
  2. 19 条款中指定的全局对象的每个属性,执行
    1. name 为该属性名的 String 值。
    2. desc 为该属性的完全填充数据属性描述符,包含该属性指定的特性。对于 19.219.319.4 中列出的属性,其 [[Value]] 为来自 realmRec 的对应内在对象。
    3. 执行 ? DefinePropertyOrThrow(global, name, desc)。
  3. 返回 unused

9.4 执行上下文 (Execution Contexts)

execution context 是规范装置,用于跟踪 ECMAScript 实现对代码的运行时求值。在任意时刻,每个 agent 最多只有一个实际执行代码的执行上下文,称为该 agent 的 运行执行上下文 (running execution context)。本规范中所有对运行执行上下文的引用均指当前 agent 的运行执行上下文。

执行上下文栈 (execution context stack) 用于跟踪执行上下文。运行执行上下文始终是该栈的顶部元素。当控制从当前运行执行上下文关联的可执行代码转移到不与其关联的可执行代码时,会创建一个新的执行上下文。新执行上下文被压入栈顶并成为运行执行上下文。

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

Table 23: 所有执行上下文的状态组成部分
组成部分 目的
code evaluation state 执行、暂停与恢复该上下文关联代码求值所需的任意状态。
Function 若该上下文正在求值某函数对象的代码,则为该函数对象;若求值 ScriptModule,该值为 null
Realm 关联代码访问 ECMAScript 资源所用的 Realm Record
ScriptOrModule 关联代码来源的 Module Record 或 Script Record。若不存在来源脚本或模块(如 InitializeHostDefinedRealm 创建的初始执行上下文),该值为 null

运行执行上下文对代码的求值可在本规范定义的各种点被挂起。一旦挂起,另一个执行上下文可成为运行执行上下文并开始求值其代码。之后某个时间,被挂起的执行上下文可再次成为运行执行上下文并从之前挂起的位置继续。运行执行上下文在不同上下文间的转换通常按堆栈后进先出方式,但某些 ECMAScript 特性需要非 LIFO 的转换。

运行执行上下文 Realm 组成部分的值也称为 当前 Realm Record。运行执行上下文 Function 组成部分的值也称为 活动函数对象 (active function object)

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

Table 24: ECMAScript 代码执行上下文的附加状态组成部分
组成部分 目的
LexicalEnvironment 标识用于解析该上下文中代码标识符引用的 Environment Record
VariableEnvironment 标识在该上下文中由 VariableStatement 创建绑定的 Environment Record
PrivateEnvironment 标识持有最近包围 class 中 ClassElement 创建的 Private NamePrivateEnvironment Record。若无包围 class 则为 null

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

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

Table 25: Generator 执行上下文的附加状态组成部分
组成部分 目的
Generator 该执行上下文正在求值的 Generator。

大多数情况下,只有运行执行上下文(执行上下文栈顶)被本规范内算法直接操作。因此当未限定使用 “LexicalEnvironment” 与 “VariableEnvironment” 时,指的是运行执行上下文的那些组成部分。

执行上下文纯属规范机制,不必对应 ECMAScript 实现中的具体实体。ECMAScript 代码无法直接访问或观察执行上下文。

9.4.1 GetActiveScriptOrModule ( )

The abstract operation GetActiveScriptOrModule takes no arguments and returns a Script Record, a Module Record, or null. 基于运行执行上下文确定运行脚本或模块。 It performs the following steps when called:

  1. 若执行上下文栈为空,返回 null
  2. ec 为执行上下文栈顶端第一个其 ScriptOrModule 组成部分不为 null 的执行上下文。
  3. 若不存在此执行上下文,返回 null;否则返回 ec 的 ScriptOrModule。

9.4.2 ResolveBinding ( name [ , env ] )

The abstract operation ResolveBinding takes argument name (a String) and optional argument env (an Environment Record or undefined) and returns either a normal completion containing a Reference Record or a throw completion. 用于确定 name 的绑定。env 可显式提供要搜索绑定的 Environment Record。 It performs the following steps when called:

  1. env 未提供或 envundefined,则
    1. env 为运行执行上下文的 LexicalEnvironment。
  2. 断言:env 是一个 Environment Record
  3. strict 为正被求值的语法产生式的 IsStrict 结果。
  4. 返回 ? GetIdentifierReference(env, name, strict)。
Note

ResolveBinding 的结果始终是一个 [[ReferencedName]] 字段为 nameReference Record

9.4.3 GetThisEnvironment ( )

The abstract operation GetThisEnvironment takes no arguments and returns an Environment Record. 查找当前提供关键字 this 绑定的 Environment Record。 It performs the following steps when called:

  1. env 为运行执行上下文的 LexicalEnvironment。
  2. 重复,
    1. existsenv.HasThisBinding()。
    2. existstrue,返回 env
    3. outerenv.[[OuterEnv]]
    4. 断言:outer 不为 null
    5. envouter
Note

步骤 2 中的循环总会终止,因为环境链最后以具有 this 绑定的全局环境结束。

9.4.4 ResolveThisBinding ( )

The abstract operation ResolveThisBinding takes no arguments and returns either a normal completion containing an ECMAScript language value or a throw completion. 使用运行执行上下文的 LexicalEnvironment 确定关键字 this 的绑定。 It performs the following steps when called:

  1. envRecGetThisEnvironment()。
  2. 返回 ? envRec.GetThisBinding()。

9.4.5 GetNewTarget ( )

The abstract operation GetNewTarget takes no arguments and returns an Object or undefined. 使用运行执行上下文的 LexicalEnvironment 确定 NewTarget 值。 It performs the following steps when called:

  1. envRecGetThisEnvironment()。
  2. 断言:envRec[[NewTarget]] 字段。
  3. 返回 envRec.[[NewTarget]]

9.4.6 GetGlobalObject ( )

The abstract operation GetGlobalObject takes no arguments and returns an Object. 返回当前运行执行上下文使用的全局对象。 It performs the following steps when called:

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

9.5 作业 (Jobs) 以及用于入队作业的宿主操作

Job(作业) 是一个无参数的抽象闭包(Abstract Closure),当当前没有其它 ECMAScript 计算正在进行时,它会启动一次 ECMAScript 计算。

作业由 ECMAScript 宿主环境在特定 agent 中调度执行。本规范描述宿主挂钩 HostEnqueueGenericJobHostEnqueueFinalizationRegistryCleanupJobHostEnqueuePromiseJobHostEnqueueTimeoutJob 来调度作业。本规范中的宿主挂钩按对作业调度施加的附加约束进行组织。宿主可定义额外的抽象操作来调度作业。此类操作接受一个 Job 抽象闭包和一个 realm(一个 Realm Recordnull)作为参数。若提供了 Realm Record,则这些操作会在拥有该 realm 的 agent 中,于未来某个时间安排执行该作业。若改为为 realm 提供 null,则该作业不求值 ECMAScript 代码。它们的实现必须符合以下要求:

  • 在未来某个时间点,当相应 agent 中没有正在运行的上下文且该 agent 的执行上下文栈为空时,实现必须:
    1. 执行任何宿主定义的准备步骤。
    2. 调用该 Job 抽象闭包。
    3. 执行任何宿主定义的清理步骤,之后执行上下文栈必须再次为空。
  • 在一个 agent 中任意时间只能有一个 Job 正在被求值。
  • 一旦开始求值某个 Job,在该 agent 中必须先运行至完成,之后才可开始另一个 Job 的求值。
  • 该抽象闭包必须返回一个正常完成(normal completion),并自行处理错误。
Note 1
宿主环境在调度方面不需要对所有 Job 一视同仁。例如,Web 浏览器与 Node.js 将处理 Promise 的 Job 视为比其它工作更高的优先级;未来特性可能添加不会设为如此高优先级的 Job。

在任意时间,若下列条件全部成立,则 scriptOrModule(一个 Script RecordModule Recordnull)是活动脚本或模块 (active script or module)

  • GetActiveScriptOrModule() 的结果为 scriptOrModule
  • scriptOrModule 是 Script RecordModule Record,令 ec 为执行上下文栈顶端第一个其 ScriptOrModule 组成部分为 scriptOrModule 的执行上下文。ecRealm 组成部分为 scriptOrModule.[[Realm]]

在任意时间,若以下条件全部成立,则某次执行已准备好求值 ECMAScript 代码 (prepared to evaluate ECMAScript code)

  • 执行上下文栈不为空。
  • 执行上下文栈顶端执行上下文的 Realm 组成部分是一个 Realm Record
Note 2

宿主环境可以通过向执行上下文栈压入执行上下文来准备执行求值代码。具体步骤由实现定义。

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

特定种类的 Job 还有额外的一致性要求。

9.5.1 JobCallback 记录 (JobCallback Records)

JobCallback Record 是用于存储一个函数对象与一个宿主定义值的 Record。通过宿主入队的 Job 调用的函数对象可能具备额外的宿主定义上下文。为传播该状态,Job 抽象闭包不应直接捕获并调用函数对象;应改用 HostMakeJobCallbackHostCallJobCallback

Note

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

JobCallback Record 具有 Table 26 中列出的字段。

Table 26: JobCallback Record 字段
字段名 含义
[[Callback]] 一个函数对象 当该 Job 被调用时要调用的函数。
[[HostDefined]] 任意(默认值 empty 保留给宿主使用的字段。

9.5.2 HostMakeJobCallback ( callback )

The host-defined abstract operation HostMakeJobCallback takes argument callback (a function object) and returns a JobCallback Record.

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

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

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

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

Note

调用发生在回调被传入负责最终调度并运行它的函数之时。例如,promise.then(thenAction) 在调用 Promise.prototype.then 时对 thenAction 调用 MakeJobCallback,而不是在调度 reaction Job 时。

9.5.3 HostCallJobCallback ( jobCallback, V, argumentsList )

The host-defined abstract operation HostCallJobCallback takes arguments jobCallback (a JobCallback Record), V (an ECMAScript language value), and argumentsList (a List of ECMAScript language values) and returns either a normal completion containing an ECMAScript language value or a throw completion.

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

  • 它必须执行并返回 Call(jobCallback.[[Callback]], V, argumentsList) 的结果。
Note

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

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

  1. 断言:IsCallable(jobCallback.[[Callback]]) 为 true
  2. 返回 ? Call(jobCallback.[[Callback]], V, argumentsList)。

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

9.5.4 HostEnqueueGenericJob ( job, realm )

The host-defined abstract operation HostEnqueueGenericJob takes arguments job (a Job Abstract Closure) and realm (a Realm Record) and returns unused. 在 realm.[[AgentSignifier]] 所指示的 agent 中,将 job 安排于未来某个时间在 realm realm 中执行。与该算法一起使用的抽象闭包意在不带额外约束(如优先级与排序)地调度。

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

9.5.5 HostEnqueuePromiseJob ( job, realm )

The host-defined abstract operation HostEnqueuePromiseJob takes arguments job (a Job Abstract Closure) and realm (a Realm Record or null) and returns unused. 安排 job 于未来某个时间执行。与该算法一起使用的抽象闭包意在与 Promise 处理相关,或以与 Promise 处理操作同等优先级被调度。

HostEnqueuePromiseJob 的实现必须符合 9.5 中的要求并且满足以下附加要求:

  • realm 不为 null,则每次 job 被调用时,实现必须执行实现定义步骤,使得在 job 调用时执行已准备好求值 ECMAScript 代码。
  • scriptOrModule 为调用 HostEnqueuePromiseJob 时的 GetActiveScriptOrModule()。若 realm 不为 null,则每次 job 被调用时,实现必须执行实现定义步骤,使得在 job 调用时 scriptOrModule 为活动脚本或模块。
  • 作业必须按调度它们的各次 HostEnqueuePromiseJob 调用的顺序运行。
Note

NewPromiseResolveThenableJob 返回的 Job 的 realm 通常是对 then 函数对象调用 GetFunctionRealm 的结果。由 NewPromiseReactionJob 返回的 Job 的 realm 通常是对处理器(若该处理器不为 undefined)调用 GetFunctionRealm 的结果。若处理器为 undefinedrealmnull。对于这两类 Job,当 GetFunctionRealm 异常完成(例如在被撤销的 Proxy 上调用)时,realm 为调用 GetFunctionRealm 时的当前 Realm Record。当 realmnull 时,不会执行用户 ECMAScript 代码,也不会创建新的 ECMAScript 对象(例如 Error 对象)。例如,WHATWG HTML 规范(https://html.spec.whatwg.org/)使用 realm 来检查脚本是否可运行,以及与 entry 概念相关。

9.5.6 HostEnqueueTimeoutJob ( timeoutJob, realm, milliseconds )

The host-defined abstract operation HostEnqueueTimeoutJob takes arguments timeoutJob (a Job Abstract Closure), realm (a Realm Record), and milliseconds (a non-negative finite Number) and returns unused. 在 realm.[[AgentSignifier]] 所指示的 agent 中,将 timeoutJob 安排于至少 milliseconds 毫秒之后在 realm realm 中执行。

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

9.6 Agents(代理)

agent(代理) 由一组 ECMAScript 执行上下文、一个执行上下文栈、一个运行执行上下文、一个 Agent Record 以及一个 执行线程 (executing thread) 组成。除执行线程外,agent 的各组成部分只属于该 agent 本身。

agent 的执行线程独立于其它 agent 在其执行上下文上执行算法步骤;但是一个执行线程可被多个 agent 共享,前提是共享该线程的 agent 中没有其 Agent Record[[CanBlock]] 字段为 true 的。

Note 1

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

当一个 agent 的执行线程在执行算法步骤时,该 agent 就是这些步骤的 包围 agent (surrounding agent)。这些步骤通过该包围 agent 访问其持有的规范级执行对象:运行执行上下文、执行上下文栈以及 Agent Record 的字段。

agent signifier(代理标识符) 是用于标识一个 Agent 的全局唯一不透明值。

Table 27: Agent Record 字段
字段名 含义
[[LittleEndian]] a Boolean 用于算法 GetValueFromBufferSetValueInBuffer 所需参数 isLittleEndian 的默认值。选择由实现定义,应为实现效率最高的选项。一旦被观察到便不可改变。
[[CanBlock]] a Boolean 决定该 agent 是否可以阻塞。
[[Signifier]] an agent signifier 在其 agent 集群内唯一标识该 agent。
[[IsLockFree1]] a Boolean 若对单字节值的原子操作无锁则为 true,否则 false
[[IsLockFree2]] a Boolean 若对双字节值的原子操作无锁则为 true,否则 false
[[IsLockFree8]] a Boolean 若对八字节值的原子操作无锁则为 true,否则 false
[[CandidateExecution]] a candidate execution Record 参见内存模型
[[KeptAlive]] a List of either Objects or Symbols 初始为空 List,表示在当前 Job 结束前需保持存活的对象和/或 symbol 列表。
[[ModuleAsyncEvaluationCount]] an integer 初始为 0,用于为异步或具有异步依赖的模块的 [[AsyncEvaluationOrder]] 字段分配递增唯一值。

一旦 [[Signifier]][[IsLockFree1]][[IsLockFree2]] 的值被 agent 集群中的任一 agent 观察到,它们就不可更改。

Note 2

[[IsLockFree1]][[IsLockFree2]] 的值不一定由硬件决定,也可反映可能随时间与实现而变的实现选择。

没有 [[IsLockFree4]] 字段:4 字节原子操作总是无锁。

实际上,如果某原子操作用任何形式的锁实现,该操作就不是无锁的。无锁不意味着无等待(wait-free):完成一个无锁原子操作需要的机器步骤数没有上界。

某大小 n 的原子访问无锁并不意味着对同大小 n 的非原子访问具备(感知的)原子性;具体来说,非原子访问仍可能分解为多个独立的内存访问。详见 ReadSharedMemoryWriteSharedMemory

Note 3

agent 是规范机制,不需对应 ECMAScript 实现中的实际产物。

9.6.1 AgentSignifier ( )

The abstract operation AgentSignifier takes no arguments and returns an agent signifier. It performs the following steps when called:

  1. AR 为包围 agent 的 Agent Record
  2. 返回 AR.[[Signifier]]

9.6.2 AgentCanSuspend ( )

The abstract operation AgentCanSuspend takes no arguments and returns a Boolean. It performs the following steps when called:

  1. AR 为包围 agent 的 Agent Record
  2. 返回 AR.[[CanBlock]]
Note

在某些环境中,对某个 agent 来说暂停可能并不合适。例如,在 Web 浏览器环境中,可能不允许暂停文档的主事件处理线程,但允许 worker 的事件处理线程暂停。

9.6.3 IncrementModuleAsyncEvaluationCount ( )

The abstract operation IncrementModuleAsyncEvaluationCount takes no arguments and returns an integer. It performs the following steps when called:

  1. AR 为包围 agent 的 Agent Record
  2. countAR.[[ModuleAsyncEvaluationCount]]
  3. AR.[[ModuleAsyncEvaluationCount]]count + 1。
  4. 返回 count
Note

该值仅用于追踪待定模块之间的相对求值顺序。实现可在没有待定模块时不可观察地将 [[ModuleAsyncEvaluationCount]] 重置为 0。

9.7 Agent Clusters(代理集群)

agent cluster(代理集群) 是能够通过操作共享内存进行通信的最大化的一组 agent。

Note 1

不同 agent 内的程序可能通过未指明的方式共享内存。至少,共享内存可包含 SharedArrayBuffer 的底层存储。

可能存在只能通过消息传递通信而不能共享内存的 agent;它们永远不在同一个 agent cluster 中。

每个 agent 恰好属于一个 agent cluster。

Note 2

集群中的 agent 不必在某个时间点全部“活着”。如果 agent A 创建了 agent B,随后 A 终止,而 B 又创建 agent C,如果 A 可以与 B 共享某些内存且 B 可以与 C 共享某些内存,则三个 agent 仍在同一集群。

同一集群内所有 agent 在其各自 Agent Record[[LittleEndian]] 字段上必须具有相同的值。

Note 3

若集群中不同 agent 的 [[LittleEndian]] 值不同,就难以在多字节数据上使用共享内存。

同一集群内所有 agent 在其 [[IsLockFree1]] 字段上必须具有相同值;[[IsLockFree2]] 字段同理。

同一集群内所有 agent 在其 [[Signifier]] 字段上必须具有不同值。

嵌入环境可在 agent 不知情或不配合的情况下停用(停止前向进展)或激活(恢复前向进展)一个 agent。若这样做,不得使集群中某些 agent 长期保持激活而另一些被无限期停用。

Note 4

上述限制的目的是避免某个 agent 因另一个被停用的 agent 而死锁或饥饿。例如,若一个生命周期独立于任何窗口文档的 HTML shared worker 被允许与这样一个独立文档的 dedicated worker 共享内存,而该文档及其 dedicated worker 被停用时 dedicated worker 持有某个锁(如文档被推入窗口历史),随后 shared worker 尝试获取该锁,那么 shared worker 会被阻塞直到 dedicated worker 被重新激活(如果会的话)。同时其它试图从其它窗口访问该 shared worker 的 worker 会饥饿。

该限制意味着无法在不属于同一“暂停/唤醒”集体的 agent 之间共享内存。

嵌入环境可以在未提前通知或未获得集群内其它 agent 协作的情况下终止某个 agent。若某 agent 的终止不是其自身或集群内其它 agent 的程序化行为,而是由集群外部因素导致,则嵌入环境必须在两个策略中择一:要么终止该集群所有 agent,要么提供可靠的 API 让集群内 agent 协调,以便至少一个仍存活的成员能够检测到该终止,并且终止数据中包含足以标识被终止 agent 的信息。

Note 5

此类终止的例子包括:操作系统或用户终止在独立进程中运行的 agent;当按 agent 资源统计显示某 agent 失控时,嵌入环境终止与其它 agent 在同一进程内运行的该 agent。

下列每个规范值以及从它们可传递抵达的值,恰好属于一个 agent cluster:

在集群中任何 agent 求值任意 ECMAScript 代码之前,集群中所有 agent 的 Agent Record[[CandidateExecution]] 字段被设为初始 candidate execution。初始 candidate execution 是一个空的 candidate execution,其 [[EventsRecords]] 字段是一个 List,其中为每个 agent 含有一个 Agent Events Record,其 [[AgentSignifier]] 字段为该 agent 的 agent signifier,而 [[EventList]][[AgentSynchronizesWith]] 字段是空 List

Note 6

同一 agent cluster 中所有 agent 在其 Agent Record[[CandidateExecution]] 字段共享同一个 candidate executioncandidate execution内存模型使用的规范机制。

Note 7

agent cluster 是规范机制,不需对应 ECMAScript 实现中的实际产物。

9.8 Forward Progress(前向进展)

某 agent 取得前向进展 (make forward progress) 指其执行根据本规范的一次求值步骤。

当一个 agent 的运行执行上下文同步且无限期地等待外部事件时,该 agent 变为 阻塞 (blocked)。只有 Agent Record[[CanBlock]] 字段为 true 的 agent 才能以此方式阻塞。未阻塞 (unblocked) 的 agent 指未阻塞的。

实现必须确保:

  • 每个拥有专用执行线程且未阻塞的 agent 最终取得前向进展
  • 共享一个执行线程的一组 agent 中,总有一个 agent 最终取得前向进展
  • 一个 agent 不得导致另一个 agent 阻塞,除非通过提供阻塞的显式 API
Note

这一点与内存模型中的活性保证一起,确保所有 seq-cst 写入最终对所有 agent 可观察。

9.9 WeakRef 与 FinalizationRegistry 目标的处理模型

9.9.1 目标 (Objectives)

本规范不保证任何对象或 symbol 会被垃圾回收。非存活的对象或 symbol 可能在很长时间后才被释放,甚至永不释放。基于此,本规范在描述被垃圾回收触发的行为时使用 “may”。

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

上述两个动作(ClearKeptObjectsCleanupFinalizationRegistry)都不得打断同步 ECMAScript 执行。由于宿主可以组合更长的同步 ECMAScript 执行段,本规范将 ClearKeptObjectsCleanupFinalizationRegistry 的调度推迟到宿主环境

一些 ECMAScript 实现包含在后台(包括 ECMAScript 空闲时)运行的垃圾回收器。让宿主环境调度 CleanupFinalizationRegistry 允许其恢复 ECMAScript 执行以运行 finalizer 工作,可能释放被持有的值,降低整体内存占用。

9.9.2 存活性 (Liveness)

对于一组对象和/或 symbol S,相对于 S 的一次 假设的 WeakRef-oblivious(弱引用无感) 执行是指:任何将其 referent 属于 SWeakRef抽象操作 WeakRefDeref 总是返回 undefined 的执行。

Note 1
WeakRef-obliviousness 与 liveness 一起捕获两个概念:其一,WeakRef 本身不会保持其 referent 存活;其二,存活性中的循环不意味着某值存活。具体地,若判定 v 的存活性依赖判定某 WeakRef referent r 的存活性,则 r 的存活性不能假定 v 的存活性,否则是循环论证。
Note 2
WeakRef-obliviousness 针对对象或 symbol 的集合而不是单个值定义,以处理循环。若对单个值定义,则一个循环中的 WeakRef referent 会被视为存活,即便其身份仅通过循环中其它 WeakRef referent 被观察。
Note 3
口语化地,若包含某个对象或 symbol 的每个集合都是存活的,则我们说该对象或 symbol 存活。

在求值任意时刻,若下列任一条件成立,则对象和/或 symbol 集合 S 被视为 live(存活)

  • S 中任一元素包含于任一 agent 的 [[KeptAlive]] List 中。
  • 存在相对于 S 的某个未来合法的假设 WeakRef-oblivious 执行,在其中观察到 S 中任一值的身份。
Note 4
第二个条件旨在捕获这样的直觉:若一个值的身份可通过非 WeakRef 手段观察到,则该值是存活的。值的身份可通过严格相等比较或作为 Map 的键被观察到。
Note 5

对象或 symbol 出现在某字段、内部槽或属性中并不意味着该值存活。例如若该值从未被返回给程序,则不可被观察。

这适用于 WeakMap 的键、WeakSet 的成员,以及 FinalizationRegistry Cell 记录的 [[WeakRefTarget]][[UnregisterToken]] 字段。

上述定义意味着:若 WeakMap 中的某键不存活,则其对应的值也不必定存活。

Note 6
Liveness 是保证引擎不得清空哪些 WeakRef 的下界。此处定义的 liveness 是不可判定的。实际中,引擎使用 reachability 等保守近似,存在较大实现自由度。

9.9.3 执行 (Execution)

在任意时刻,若一组对象和/或 symbol S 不存活,ECMAScript 实现可原子地执行以下步骤:

  1. 对于 S 的每个元素 value,执行
    1. 对每个 WeakRef refref.[[WeakRefTarget]]value),执行
      1. ref.[[WeakRefTarget]]empty
    2. 对每个 FinalizationRegistry fgfg.[[Cells]] 含有记录 cellcell.[[WeakRefTarget]]value),执行
      1. cell.[[WeakRefTarget]]empty
      2. 可选:执行 HostEnqueueFinalizationRegistryCleanupJob(fg)。
    3. 对每个 WeakMap mapmap.[[WeakMapData]] 含有记录 rr.[[Key]]value),执行
      1. r.[[Key]]empty
      2. r.[[Value]]empty
    4. 对每个 WeakSet setset.[[WeakSetData]] 含有 value),执行
      1. set.[[WeakSetData]] 中值为 value 的元素替换为值为 empty 的元素。
Note 1

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

可能存在在不观察对象身份的情况下访问对象的情形。诸如死变量消除、对非逃逸对象属性的标量替换等优化在对象身份未被观察时允许进行。因此,这些优化可在可观察范围内清空指向此类对象的 WeakRef

另一方面,若对象身份可被观察且该对象位于某 WeakRef[[WeakRefTarget]] 内部槽中,则诸如重新物化(rematerialization)等会在可观察层面清空该 WeakRef 的优化被禁止。

由于调用 HostEnqueueFinalizationRegistryCleanupJob 是可选的,注册在 FinalizationRegistry 中的对象不必定保持该 FinalizationRegistry 存活。实现可基于任何理由省略 FinalizationRegistry 回调,例如 FinalizationRegistry 自身变为“死”,或应用正在关闭。

Note 2

实现不要求针对最大的不存活对象或 symbol 集合清空 WeakRef

若实现选择一个不存活集合 S 来清空 WeakRef,此定义要求它同时清空 S 中所有值的 WeakRef。换言之,实现不能只清空指向值 vWeakRef 而保留其它可能在执行中观察到 vWeakRef 未清空。

9.9.4 宿主挂钩 (Host Hooks)

9.9.4.1 HostEnqueueFinalizationRegistryCleanupJob ( finalizationRegistry )

The host-defined abstract operation HostEnqueueFinalizationRegistryCleanupJob takes argument finalizationRegistry (a FinalizationRegistry) and returns unused.

cleanupJob 为一个无参数的新 Job 抽象闭包,它捕获 finalizationRegistry 并在被调用时执行以下步骤:

  1. cleanupResultCompletion(CleanupFinalizationRegistry(finalizationRegistry))。
  2. cleanupResult异常完成,执行任意宿主定义步骤以报告错误。
  3. 返回 unused

HostEnqueueFinalizationRegistryCleanupJob 的实现将 cleanupJob 安排于未来某个时间(若可能)执行,并且还必须符合 9.5 中的要求。

9.10 ClearKeptObjects ( )

The abstract operation ClearKeptObjects takes no arguments and returns unused. 期望 ECMAScript 实现在一次同步的 ECMAScript 执行序列完成后调用 ClearKeptObjects。 It performs the following steps when called:

  1. agentRecord 为包围 agent 的 Agent Record
  2. agentRecord.[[KeptAlive]] 为一个新的空 List
  3. 返回 unused

9.11 AddToKeptObjects ( value )

The abstract operation AddToKeptObjects takes argument value (an Object or a Symbol) and returns unused. It performs the following steps when called:

  1. agentRecord 为包围 agent 的 Agent Record
  2. value 追加到 agentRecord.[[KeptAlive]]
  3. 返回 unused
Note
抽象操作 AddToKeptObjects 以某目标对象或 symbol 被调用时,它把该目标加入一个列表;在调用 ClearKeptObjects 之前,该列表会对目标保持强引用。

9.12 CleanupFinalizationRegistry ( finalizationRegistry )

The abstract operation CleanupFinalizationRegistry takes argument finalizationRegistry (a FinalizationRegistry) and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. 断言:finalizationRegistry 具有 [[Cells]][[CleanupCallback]] 内部槽。
  2. callbackfinalizationRegistry.[[CleanupCallback]]
  3. finalizationRegistry.[[Cells]] 含有某记录 cellcell.[[WeakRefTarget]]empty 时,实现可以执行以下步骤:
    1. 任选一个这样的 cell
    2. finalizationRegistry.[[Cells]] 中移除 cell
    3. 执行 ? HostCallJobCallback(callback, undefined, « cell.[[HeldValue]] »)。
  4. 返回 unused

9.13 CanBeHeldWeakly ( v )

The abstract operation CanBeHeldWeakly takes argument v (an ECMAScript language value) and returns a Boolean. 当且仅当 v 适合作为弱引用使用时返回 true。只有适合作为弱引用使用的值才能成为 WeakMap 的键、WeakSet 的元素、WeakRef 的 target,或 FinalizationRegistry 的某个 target。 It performs the following steps when called:

  1. v 是一个 Object,返回 true
  2. v 是一个 Symbol 且 KeyForSymbol(v) 为 undefined,返回 true
  3. 返回 false
Note

没有 语言身份 (language identity) 的语言值可以在没有先前引用的情况下被重新生成,不适合作为弱引用。由 Symbol.for 产生的 Symbol 值与其他 Symbol 不同,它不具有语言身份,因此也不适合作为弱引用。Well-known symbols 很可能永远不会被回收,但由于其数量有限,仍被视为适合用作弱引用,可通过多种实现手段管理。然而,在一个存活的 WeakMap 中与某个 well-known symbol 关联的任何值都不太可能被回收,可能在实现中“泄漏”内存资源。