1. 简介
本节为资料性内容。
本标准定义了一种接口定义语言 Web IDL,可用于描述拟在 Web 浏览器中实现的接口。Web IDL 是一种 IDL 变体,具有许多特性,能够更容易地指定 Web 平台中常见脚本对象的行为。还详细说明了使用 Web IDL 描述的接口如何与 JavaScript 执行环境中的构造相对应。
具体而言,Web IDL 提供了一种语法,用于指定 Web 平台对象的表面 API 以及 JavaScript 绑定,详细说明了这些 API 如何以 JavaScript 构造的形式体现。这确保了常见任务(例如安装全局属性、处理数值输入或暴露迭代行为)在各个 Web 平台规范中保持统一:这些规范使用 Web IDL 描述其接口,然后使用文章来指定 API 特定的细节。
术语“JavaScript”用于指代 ECMA-262,而不是官方术语 ECMAScript,因为 JavaScript 这一术语更为人所熟知。
2. 接口定义语言
本节描述了一种语言,Web IDL,可以用于为 Web 平台中的 API 定义接口。定义 Web API 的规范可以包含一个或多个 IDL 片段,
描述该规范所定义的 API 的接口(对象可以展示的状态和行为)。
一个 IDL 片段 是一系列与
可以出现在 IDL 片段 中的各种 定义 包括:接口,部分接口定义,接口混入,部分混入定义,回调函数,回调接口,命名空间,部分命名空间定义,字典,部分字典定义,类型定义 以及 包含声明。 这些定义将在以下部分中进行详细定义。
每个 定义(与
[扩展属性 ]接口 标识符 { /* 接口成员... */ };
Definitions ::ExtendedAttributeList Definition Definitions ε
Definition ::CallbackOrInterfaceOrMixin Namespace Partial Dictionary Enum Typedef IncludesStatement
以下是一个 IDL 片段 的示例。
[暴露 =Window ]接口 Paint { }; [暴露 =Window ]接口 SolidColor :Paint {属性 双精度浮点数 red ;属性 双精度浮点数 green ;属性 双精度浮点数 blue ; }; [暴露 =Window ]接口 Pattern :Paint {属性 DOMString imageURL ; }; [暴露 =Window ]接口 GraphicalWindow {构造函数 ();只读 属性 无符号 长整数 width ;只读 属性 无符号 长整数 height ;属性 Paint currentPaint ;未定义 drawRectangle (双精度浮点数 x ,双精度浮点数 y ,双精度浮点数 width ,双精度浮点数 height );未定义 drawText (双精度浮点数 x ,双精度浮点数 y ,DOMString text ); };
在此,定义了四个 接口。
GraphicalWindow
接口有两个 只读 属性,
一个可写属性,以及两个 操作。实现 GraphicalWindow
接口的对象将以适合使用的语言的方式暴露这些属性和操作。
在 JavaScript 中,IDL 接口上的属性将作为访问器属性暴露,
操作将作为数据属性,其值为 内置函数对象,
位于所有 GraphicalWindow
对象的原型对象中;每个实现 GraphicalWindow
的
JavaScript 对象都会在其原型链中包含该原型对象。
出现在 GraphicalWindow
上的 构造函数操作 导致在 JavaScript 实现中存在一个 构造函数,
因此调用 new GraphicalWindow()
将返回一个实现了该接口的新对象。
2.1. 名称
每个 接口,部分接口定义,命名空间,部分命名空间定义,字典,部分字典定义,枚举,回调函数,回调接口 和 类型定义
(统称为 命名定义)
以及每个 常量,属性,
和 字典成员 都有一个
标识符,某些 操作 也有。
该标识符通过声明中的
-
对于 命名定义, 在
identifier 令牌紧接interface 、namespace 、dictionary 、enum 或callback 关键字出现时确定该定义的标识符。interface interface_identifier { /* interface_members... */ };partial interface interface_identifier { /* interface_members... */ };namespace namespace_identifier { /* namespace_members... */ };partial namespace namespace_identifier { /* namespace_members... */ };dictionary dictionary_identifier { /* dictionary_members... */ };partial dictionary dictionary_identifier { /* dictionary_members... */ };enum enumeration_identifier {"enum" ,"values" /* , ... */ };callback callback_identifier =return_type (/* arguments... */);callback interface callback_interface_identifier { /* interface_members... */ }; -
对于 属性,类型定义 和 字典成员, 在声明末尾分号前的最终
identifier 令牌确定标识符。[
extended_attributes ]interface identifier {attribute type attribute_identifier ; };typedef type typedef_identifier ;dictionary identifier {type dictionary_member_identifier ; }; -
对于 常量, 在等号之前的
identifier 令牌确定标识符。const type constant_identifier = 42; -
对于 操作,在返回类型之后但在左括号之前出现的
identifier 令牌(即,与OptionalOperationName 语法符号中的一部分匹配)决定该操作的标识符。如果没有这样的identifier 令牌,则该操作没有标识符。interface interface_identifier {return_type operation_identifier (/* arguments... */); };
注意: 当用于声明 特殊类型的操作(如 getter 或 setter)时,操作可以没有标识符。
对于所有这些构造,标识符 是删除任何前导
U+005F (_) 后的
注意: 前导 U+005F (_)
用于防止标识符看起来像保留字,例如,可以定义一个名为“interface
”的接口。前导 U+005F (_) 会被删除以取消转义标识符。
操作参数可以采用稍微宽泛的标识符集。在操作声明中,参数的标识符在其类型之后立即指定,由
interface interface_identifier {return_type operation_identifier (argument_type argument_identifier /* , ... */); };
ArgumentNameKeyword ::async attribute callback const constructor deleter dictionary enum getter includes inherit interface iterable maplike mixin namespace partial readonly required setlike setter static stringifier typedef unrestricted
如果使用了
上述 IDL 构造的任何一个的 标识符(操作参数除外)不得为 "constructor
"、
"toString
" 或以 U+005F (_) 开头。这些被称为 保留标识符。
尽管 "toJSON
" 标识符
不是 保留标识符,
但它必须仅用于将对象转换为 JSON 类型 的 常规操作,如 § 2.5.3.1 toJSON 所述。
注意: 某些构造的标识符名称可能在后续部分中有进一步限制。
在给定实现支持的 IDL 片段 集合中,每个 接口、命名空间、字典、枚举、回调函数、回调接口 和 类型定义 的 标识符 不得与任何其他 接口、命名空间、字典、枚举、回调函数、回调接口 或 类型定义 的标识符相同。
在 IDL 片段 中,对 定义 的引用无需出现在所引用定义的声明之后。引用也可以跨 IDL 片段 进行。
因此,以下 IDL 片段 是有效的:
[Exposed =Window ]interface B :A {undefined f (SequenceOfLongs x ); }; [Exposed =Window ]interface A { };typedef sequence <long >SequenceOfLongs ;
以下 IDL 片段 展示了如何为定义和 接口成员 赋予标识符。
// Typedef identifier: "number"typedef double number ; // Interface identifier: "System" [Exposed =Window ]interface System { // Operation identifier: "createObject" // Operation argument identifier: "interface"object createObject (DOMString _interface ); // Operation argument identifier: "interface"sequence <object >getObjects (DOMString interface ); // Operation has no identifier; it declares a getter.getter DOMString (DOMString keyName ); }; // Interface identifier: "TextField" [Exposed =Window ]interface TextField { // Attribute identifier: "const"attribute boolean _const ; // Attribute identifier: "value"attribute DOMString ?_value ; };
请注意,虽然 TextField
接口上的第二个 属性不需要使用下划线转义(因为 "value
" 不是 IDL
语法中的关键字),但它仍然会被解除转义以获得该属性的 标识符。
2.2. 接口
IDL
片段用于描述面向对象的系统。在这些系统中,对象是具有标识性并封装状态和行为的实体。接口是一个定义(匹配
[extended_attributes ]interface identifier { /* interface_members... */ };
接口是 接口成员(匹配
Web IDL 中的接口描述了实现该接口的对象的行为。在面向对象语言的绑定中,预计实现特定 IDL 接口的对象提供检查和修改对象状态以及调用接口描述的行为的方式。
接口可以定义为从另一个接口继承。如果接口的标识符后跟 U+003A (:) 和一个标识符,那么该标识符标识继承的接口。实现继承接口的对象也将实现该继承接口。因此,对象还将拥有与继承接口的接口成员相对应的成员。
interface identifier :identifier_of_inherited_interface { /* interface_members... */ };
成员出现的顺序对JavaScript 绑定中的属性枚举具有重要意义。
接口可以指定一个与继承接口中的同名接口成员。实现派生接口的对象将在派生接口上公开该成员。是否可以在对象上访问被覆盖的成员取决于语言绑定的具体情况。
请考虑以下两个接口。
[Exposed =Window ]interface A {undefined f ();undefined g (); }; [Exposed =Window ]interface B :A {undefined f ();undefined g (DOMString x ); };
在 JavaScript 语言绑定中,B
的实例将拥有如下的原型链:
[Object.prototype: the Object prototype object] ↑ [A.prototype: interface prototype object for A] ↑ [B.prototype: interface prototype object for B] ↑ [instanceOfB]
在 JavaScript 中调用instanceOfB.f()
将调用定义在B
上的f。然而,可以通过调用A.prototype.f.call(instanceOfB)
在实现B
的对象上仍然调用A
中的f。
给定接口A的继承接口是A直接或间接继承的所有接口的集合。如果A不从另一个接口继承,则集合为空。否则,集合包括A继承的接口B以及B的所有继承接口。
接口声明不得使其继承层次结构形成循环。即,接口A不能继承自它自身,也不能继承自继承自A的另一个接口B,等等。
请注意,一般的接口多重继承不被支持,且对象也不能实现任意集合的接口。可以定义对象来实现给定的单个接口A,这意味着它也实现了A的所有继承接口。此外,可以使用includes 语句来定义实现接口A的对象将始终包含A 接口混入的成员。
每个接口成员前可以有一个扩展属性列表(匹配
[extended_attributes ]interface identifier { [extended_attributes ]const type constant_identifier = 42; [extended_attributes ]attribute type identifier ; [extended_attributes ]return_type identifier (/* arguments... */); };
接口的 IDL 可以通过使用部分接口定义(匹配
interface SomeInterface { /* interface_members... */ };partial interface SomeInterface { /* interface_members... */ };
注意:部分接口定义旨在作为规范编辑辅助工具,允许将接口定义分散在文档的多个部分,有时甚至是多个文档中。
接口定义及其任何部分接口定义的出现顺序没有关系。
注意:部分接口定义不能指定接口继承自另一个接口。继承必须在原始接口定义中指定。
相关语言绑定决定接口如何对应于该语言中的结构。
以下扩展属性适用于接口:[CrossOriginIsolated
],[Exposed
],[Global
],[LegacyFactoryFunction
],[LegacyNoInterfaceObject
],[LegacyOverrideBuiltIns
],[LegacyWindowAlias
],以及[SecureContext
]。
以下扩展属性适用于部分接口:[CrossOriginIsolated
],[Exposed
],[LegacyOverrideBuiltIns
],以及[SecureContext
]。
接口interface的限定名称定义如下:
-
令identifier为interface的标识符。
-
如果interface具有[
LegacyNamespace
]扩展属性,则:-
令namespace为[
LegacyNamespace
]扩展属性的标识符参数。 -
返回由namespace和identifier的连接,用分隔符 U+002E (.)。
-
-
返回identifier。
CallbackOrInterfaceOrMixin ::callback CallbackRestOrInterface interface InterfaceOrMixin
InterfaceOrMixin ::InterfaceRest MixinRest
InterfaceRest ::identifier Inheritance { InterfaceMembers } ;
Partial ::partial PartialDefinition
PartialDefinition ::interface PartialInterfaceOrPartialMixin PartialDictionary Namespace
PartialInterfaceOrPartialMixin ::PartialInterfaceRest MixinRest
PartialInterfaceRest ::identifier { PartialInterfaceMembers } ;
InterfaceMembers ::ExtendedAttributeList InterfaceMember InterfaceMembers ε
InterfaceMember ::PartialInterfaceMember Constructor
PartialInterfaceMembers ::ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers ε
PartialInterfaceMember ::Const Operation Stringifier StaticMember Iterable AsyncIterable ReadOnlyMember ReadWriteAttribute ReadWriteMaplike ReadWriteSetlike InheritAttribute
Inheritance ::: identifier ε
以下IDL 片段展示了两个相互引用的接口的定义。Human
和Dog
都继承自Animal
。实现这两个接口中的任意一个的对象都将具有name
属性。
[Exposed =Window ]interface Animal {attribute DOMString name ; }; [Exposed =Window ]interface Human :Animal {attribute Dog ?pet ; }; [Exposed =Window ]interface Dog :Animal {attribute Human ?owner ; };
以下IDL 片段定义了简化版本的 DOM 接口和一个回调接口。
[Exposed =Window ]interface Node {readonly attribute DOMString nodeName ;readonly attribute Node ?parentNode ;Node appendChild (Node newChild );undefined addEventListener (DOMString type ,EventListener listener ); };callback interface EventListener {undefined handleEvent (Event event ); };
普通对象可以实现一个回调接口,如EventListener
:
var node= getNode(); // 获取 Node 实例。 var listener= { handleEvent: function ( event) { // ... } }; node. addEventListener( "click" , listener); // 这可以正常工作。 node. addEventListener( "click" , function () { ... }); // 这也是可以的。
然而,这类对象无法实现一个接口,比如Node
:
var node= getNode(); // 获取 Node 实例。 var newNode= { nodeName: "span" , parentNode: null , appendChild: function ( newchild) { // ... }, addEventListener: function ( type, listener) { // ... } }; node. appendChild( newNode); // 这将抛出一个 TypeError 异常。
2.3. 接口混入
接口混入 是一个定义(匹配
interface mixin identifier { /* mixin_members... */ };
注意:接口混入与部分接口类似,旨在作为规范编辑的工具,允许将一组功能归为一组,并在多个接口中包含,可能跨多个文档。它们不打算通过语言绑定暴露。有关何时选择部分接口、接口混入或部分接口混入的指导可以在§ 2.3.1 使用混入和部分接口中找到。
接口混入是常量、常规操作、常规属性和字符串化器的集合描述,它们是定义在接口混入声明中的。
这些常量、常规操作、常规属性和字符串化器描述了可以由对象实现的行为,就好像它们是由接口指定的一样,这些接口包含了这些混入。
与接口一样,接口混入的IDL可以通过使用部分接口混入定义分成多个部分(匹配
interface mixin SomeMixin { /* mixin_members... */ };partial interface mixin SomeMixin { /* mixin_members... */ };
接口成员的出现顺序在JavaScript绑定中的属性枚举具有意义。
在本规范中定义的扩展属性中,只有[CrossOriginIsolated
]、[Exposed
]和[SecureContext
]适用于接口混入。
包含语句 是一个定义(匹配
interface_identifier includes mixin_identifier ;
第一个标识符必须引用一个接口I。第二个标识符必须引用一个接口混入M。
M的每个成员都被视为每个接口 I、J、K 等的成员,这些接口包含M,就好像每个成员都被复制了一样。因此,对于M的某个成员m,接口I被认为有一个成员mI,接口J被认为有一个成员mJ,接口K被认为有一个成员mK,以此类推。mI、mJ 和 mK 的宿主接口分别是I、J 和 K。
注意:在 JavaScript 中,这意味着每个作为成员声明的接口混入M的常规操作,并作为具有内置函数对象值的数据属性公开的,在每个包含混入M的接口的接口原型对象中都是一个独立的内置函数对象。同样,对于属性,每个访问器属性的副本都有独立的内置函数对象用于其获取器和设置器。
includes 声明的出现顺序会影响接口混入被其宿主接口 包含的顺序。
成员的顺序并没有明确规定,特别是当接口混入在不同文档中定义时。这在问题 #432中有所讨论。
本规范中定义的扩展属性不适用于includes 声明。
以下IDL 片段定义了一个接口,Entry
,以及一个接口混入,Observable
。includes 声明指定了Observable
的成员会始终包含在实现Entry
的对象上。
interface Entry {readonly attribute unsigned short entryType ; // ... };interface mixin Observable {undefined addEventListener (DOMString type ,EventListener listener ,boolean useCapture ); // ... };Entry includes Observable ;
因此,在 JavaScript 实现中,每个Entry
的原型链上都会有一个addEventListener
属性:
var e= getEntry(); // 获取一个 Entry 的实例。 typeof e. addEventListener; // 结果为 "function"。
CallbackOrInterfaceOrMixin ::callback CallbackRestOrInterface interface InterfaceOrMixin
Partial ::partial PartialDefinition
MixinRest ::mixin identifier { MixinMembers } ;
MixinMembers ::ExtendedAttributeList MixinMember MixinMembers ε
MixinMember ::Const RegularOperation Stringifier OptionalReadOnly AttributeRest
IncludesStatement ::identifier includes identifier ;
2.3.1. 使用 mixins 和 partials
本节是说明性的。
接口混入允许在多个 接口之间共享属性、常量和操作。如果你只打算扩展一个接口,可以考虑使用部分接口。
例如,不要这样做:
interface mixin WindowSessionStorage {readonly attribute Storage sessionStorage ; };Window includes WindowSessionStorage ;
可以这样做:
partial interface Window {readonly attribute Storage sessionStorage ; };
此外,你还可以依赖其他规范中暴露的接口混入,以针对常见用例,如在窗口和工作线程上下文中暴露一组属性、常量或操作。
例如,与其使用常见但冗长的方式:
interface mixin GlobalCrypto {readonly attribute Crypto crypto ; };Window includes GlobalCrypto ;WorkerGlobalScope includes GlobalCrypto ;
你可以使用部分接口混入扩展WindowOrWorkerGlobalScope
接口混入:
partial interface mixin WindowOrWorkerGlobalScope {readonly attribute Crypto crypto ; };
2.4. 回调接口
回调接口是一个符合
注意: 回调接口不是一个接口。其名称和语法来源于本标准的早期版本,当时这些概念有更多的共通点。
回调接口是对一组回调接口成员(符合
callback interface identifier { /* interface_members... */ };
注意: 另请参阅类似名称的回调函数定义。
规范作者不应定义回调接口,除非需要描述现有 API 的要求。相反,应使用回调函数。
将EventListener
定义为回调接口是一个例子,它需要允许具有特定属性(此处为handleEvent
)的对象被认为实现了该接口。对于新 API 以及没有兼容性问题的 API,使用回调函数将仅允许函数对象(在 JavaScript 语言绑定中)。
回调接口如果声明了常量,必须使用 [Exposed
] 扩展属性进行注释。
CallbackRestOrInterface ::CallbackRest interface identifier { CallbackInterfaceMembers } ;
CallbackInterfaceMembers ::ExtendedAttributeList CallbackInterfaceMember CallbackInterfaceMembers ε
CallbackInterfaceMember ::Const RegularOperation
2.5. 成员
接口, 接口混入, 和 命名空间 是一组 成员
的规范(分别对应
对于在 接口 或 接口混入 上定义的各种 成员,其 构造函数步骤、 getter 步骤、setter 步骤 和 方法步骤 可以访问 this 值,该值是 接口 类型的 IDL 值,其成员是在其声明中或 包含 接口混入 中声明的成员。
Setter 步骤 还可以访问 给定值, 该值是 属性 声明的类型的 IDL 值。
接口、接口混入、回调接口 和 命名空间 各自支持不同的 成员 集合, 其分别在 § 2.2 接口、§ 2.3 接口混入、§ 2.4 回调接口 和 § 2.6 命名空间 中规定,并在以下信息表中总结:
接口 | 回调接口 | 接口混入 | 命名空间 | |
---|---|---|---|---|
常量 | ● | ● | ● | |
常规属性 | ● | ● | 仅 只读 属性 | |
静态属性 | ● | |||
常规操作 | ● | ● | ● | ● |
字符串化器 | ● | ● | ||
特殊操作 | ● | |||
静态操作 | ● | |||
可迭代声明 | ● | |||
异步可迭代声明 | ● | |||
类似Map的声明 | ● | |||
类似Set的声明 | ● |
2.5.1. 常量
常量 是一个声明(对应
过去常量主要用于以枚举方式定义命名的整数代码。Web 平台正在逐步远离这种设计模式,转而使用字符串。 编辑希望使用此功能时,强烈建议在继续之前通过 提交问题 进行讨论。
const type constant_identifier = 42;
标识符不能与另一个定义在相同 接口 或 回调接口 上的 接口成员 或 回调接口成员 的标识符相同。
此外,标识符不能为 "length
", "name
" 或 "prototype
"。
注意: 这三个名称是 JavaScript 语言绑定中定义在 接口对象 上的属性名称。
常量的类型(对应
常量声明的
注意: 除了字符串和空序列之外,这些值还可用于指定 字典成员的默认值 或 可选参数的默认值。
请注意,字符串、空序列
布尔字面量标记 boolean
值
true
和 false
。
整数标记
常量值为
- 类型
无限制浮点数
,常量值Infinity -
值为 IEEE 754 单精度正无穷大值。
- 类型
无限制双精度浮点数
,常量值Infinity -
值为 IEEE 754 双精度正无穷大值。
- 类型
无限制浮点数
,常量值-Infinity -
值为 IEEE 754 单精度负无穷大值。
- 类型
无限制双精度浮点数
,常量值-Infinity -
值为 IEEE 754 双精度负无穷大值。
- 类型
无限制浮点数
,常量值NaN -
值为 IEEE 754 单精度 NaN 值,位模式为 0x7fc00000。
- 类型
无限制双精度浮点数
,常量值NaN -
值为 IEEE 754 双精度 NaN 值,位模式为 0x7ff8000000000000。
float
或
double
的值。
如果 VT 是分配给常量的值的类型,DT 是常量、字典成员或可选参数本身的类型,那么这些类型必须 兼容,兼容的情况是 DT 和 VT 相同, 或者 DT 是其 内部类型 为 VT 的 可为空类型。
常量 与出现在它们上的特定 接口 或 回调接口 的实例无关。是否在实例上暴露 常量 取决于语言绑定。
然而,JavaScript 语言绑定允许通过实现了声明 常量 的 IDL 接口 的对象访问常量。 例如,以下 IDL:
[Exposed =Window ]interface A {const short rambaldi = 47; };
在 JavaScript 中可以通过 A.rambaldi
或 instanceOfA.rambaldi
访问常量值。
以下扩展属性适用于常量:
[CrossOriginIsolated
],
[Exposed
] 和
[SecureContext
]。
Const ::const ConstType identifier = ConstValue ;
ConstValue ::布尔字面量 浮点字面量 整数
布尔字面量 ::true false
浮点字面量 ::小数 -Infinity Infinity NaN
ConstType ::原始类型 标识符
[Exposed =Window ]interface Util {const boolean DEBUG =false ;const octet LF = 10;const unsigned long BIT_MASK = 0x0000fc00;const double AVOGADRO = 6.022e23; };
2.5.2. 属性
属性 是一个 接口成员 或 命名空间成员(对应
-
常规属性,用于声明实现 接口 的对象将拥有带有给定 标识符 的数据字段成员。
interface interface_identifier {attribute type identifier ; }; -
静态属性,用于声明与实现接口的特定对象无关的属性。
interface interface_identifier {static attribute type identifier ; };
如果属性没有
属性 attr 的 getter
步骤 应以类似“attr
getter 步骤如下:”的文字介绍,后跟列表,或以“attr
getter 步骤是”开头,后跟内联描述。
属性 attr 的 setter
步骤 应以类似“attr
setter 步骤如下:”的文字介绍,后跟列表,或以“attr
setter 步骤是”开头,后跟内联描述。
注意: 定义 getter 步骤 时,隐式访问 this。 定义 setter 步骤 时,隐式访问 this 和 给定值。
属性的 标识符不得与相同 接口 上定义的另一个 接口成员 的标识符相同。
静态属性的标识符不得为 "prototype
"。
属性的类型由出现在
在解析 typedef 后,属性的类型不能是以下任何类型的 可为空 或不可为空的版本:
如果在
interface interface_identifier {readonly attribute type identifier ; };
类型为 Promise 类型 的属性必须是 只读 的。此外,它们不能拥有
以下任何 扩展属性:[LegacyLenientSetter
],
[PutForwards
],
[Replaceable
],
或
[SameObject
]。
非 只读 的 常规属性 可以声明为从祖先接口继承其 getter。
这可以用于使祖先接口中的只读属性在派生接口上可写。
如果声明中包含
注意: 语法确保
[Exposed =Window ]interface Ancestor {readonly attribute TheType theIdentifier ; }; [Exposed =Window ]interface Derived :Ancestor {inherit attribute TheType theIdentifier ; };
当在 常规属性 声明中使用
interface interface_identifier {stringifier attribute DOMString identifier ; };
以下 扩展属性
适用于常规和静态属性:
[CrossOriginIsolated
],
[Exposed
],
[SameObject
],
和
[SecureContext
]。
以下 扩展属性
仅适用于常规属性:
[LegacyLenientSetter
],
[LegacyLenientThis
],
[PutForwards
],
[Replaceable
],
[LegacyUnforgeable
]。
ReadOnlyMember ::readonly ReadOnlyMemberRest
ReadOnlyMemberRest ::AttributeRest MaplikeRest SetlikeRest
ReadWriteAttribute ::AttributeRest
InheritAttribute ::inherit AttributeRest
AttributeRest ::attribute TypeWithExtendedAttributes AttributeName ;
AttributeName ::AttributeNameKeyword identifier
AttributeNameKeyword ::async required
OptionalReadOnly ::readonly ε
[Exposed =Window ]interface Animal { // 一个可以设置为任何字符串值的简单属性。readonly attribute DOMString name ; // 一个属性,其值可以被分配。attribute unsigned short age ; }; [Exposed =Window ]interface Person :Animal { // 一个从 Animal 继承 getter 行为的属性,不需要在 Person 的描述中指定。inherit attribute DOMString name ; };
2.5.3. 操作
一个操作是一个接口成员、回调接口成员或命名空间成员(匹配
-
常规操作, 用于声明实现 接口 的对象将拥有具有给定 标识符 的方法。
interface interface_identifier {return_type identifier (/* arguments... */); }; -
特殊操作, 用于在实现接口的对象上声明特殊行为,例如对象索引和字符串化
interface interface_identifier { /* special_keyword */return_type identifier (/* arguments... */); /* special_keyword */return_type (/* arguments... */); }; -
静态操作, 用于声明与实现接口的特定对象无关的操作。
interface interface_identifier {static return_type identifier (/* arguments... */); };
如果一个操作有标识符但没有
如果操作没有标识符, 则必须使用其中一个特殊关键字将其声明为特殊操作。
常规操作 或 静态操作 的标识符不得与在相同
接口、回调接口 或 命名空间 上定义的 常量 或 属性 的标识符相同。
静态操作的标识符不得为 "prototype
"。
注意: 然而,标识符可以与接口上其他操作的标识符相同。 这是指定操作重载的方式。
注意: 静态操作 的标识符可以与在相同 接口 上定义的 常规操作 的标识符相同。
操作的 返回类型 由
出现在操作的可选 标识符 之前的类型(对应
操作的参数(对应
注意: 为了表达的灵活性,操作参数的标识符还可以指定为
匹配
如果操作参数的
如果操作参数的类型在解析 typedef 后, 是 可为空类型, 则其 内部类型 不能是 字典类型。
interface interface_identifier {return_type identifier (type identifier ,type identifier /* , ... */); };
每个参数的标识符不得与相同操作声明中的其他参数标识符相同。
每个参数可以有一个前置的 扩展属性 列表(对应
interface interface_identifier {return_type identifier ([extended_attributes ]type identifier , [extended_attributes ]type identifier /* , ... */); };
[Exposed =Window ]interface Dimensions {attribute unsigned long width ;attribute unsigned long height ; }; [Exposed =Window ]interface Button { // 一个不带参数并返回布尔值的操作。boolean isMouseOver (); // 重载的操作。undefined setDimensions (Dimensions size );undefined setDimensions (unsigned long width ,unsigned long height ); };
操作或 构造器操作 被视为 可变参数,如果最后一个参数使用
interface interface_identifier {return_type identifier (type ...identifier );return_type identifier (type identifier ,type ...identifier ); };
扩展属性
使用参数列表的情况(例如 [LegacyFactoryFunction
])和
回调函数,当其参数列表中使用
以下 IDL 片段 定义了具有两个可变参数操作的接口:
[Exposed =Window ]interface IntegerSet {readonly attribute unsigned long cardinality ;undefined union (long ...ints );undefined intersection (long ...ints ); };
在 JavaScript 绑定中,可变参数操作通过可以接受后续参数的函数来实现:
var s= getIntegerSet(); // 获取 IntegerSet 的实例。 s. union(); // 不传递与 'ints' 对应的参数。 s. union( 1 , 4 , 7 ); // 传递三个与 'ints' 对应的参数。
对于不支持可变参数函数的语言绑定,可以指定传递一个显式数组或整数列表给这样的操作。
如果参数使用了
interface interface_identifier {return_type identifier (type identifier ,optional type identifier ); };
可选参数还可以有 默认值。如果参数的标识符后跟 U+003D (=) 和一个值(对应
interface interface_identifier {return_type identifier (type identifier ,optional type identifier = "value"); };
强烈建议不要为 boolean
类型的参数使用默认值
如果参数的类型是 字典类型 或 联合类型,且其具有 字典类型 作为其 展平的成员类型之一,并且该字典类型及其祖先没有 必需 成员,并且该参数是最后一个参数或后面仅跟有 可选参数,则该参数必须指定为可选并提供默认值。
这鼓励 API 设计不要求作者传递一个空字典值,只希望使用字典的默认值。
通常提供的默认值将是
当布尔文字标记(
当 undefined
值。
如果 可选参数 的类型是 枚举类型,则其 默认值,如果指定,必须是 枚举的值之一。
可选参数的默认值还可以使用两个标记值
可选参数默认值也可以使用双标记值
以下 IDL 片段 定义了一个具有单个可以用两种不同参数列表长度调用的 操作的 接口:
[Exposed =Window ]interface ColorCreator {object createColor (double v1 ,double v2 ,double v3 ,optional double alpha ); };
[Exposed =Window ]interface ColorCreator {object createColor (double v1 ,double v2 ,double v3 );object createColor (double v1 ,double v2 ,double v3 ,double alpha ); };
dictionary LookupOptions {boolean caseSensitive =false ; }; [Exposed =Window ]interface AddressBook {boolean hasAddressForName (USVString name ,optional LookupOptions options = {}); };
如果 hasAddressForName
只用一个参数调用,第二个参数将是一个默认初始化的 LookupOptions
字典,这将使
caseSensitive
设置为
以下扩展属性适用于操作:[CrossOriginIsolated
],[Default
],[Exposed
],[LegacyUnforgeable
],[NewObject
],和
[SecureContext
]。
一个操作 operation 的 方法步骤
应使用如下格式的文本引入:“operation(arg1, arg2, ...)
方法步骤如下:”后跟一个列表,或者“operation(arg1, arg2, ...)
方法步骤是为了”后跟一个内联描述。
DefaultValue ::ConstValue string [ ] { } null undefined
Operation ::RegularOperation SpecialOperation
RegularOperation ::Type OperationRest
SpecialOperation ::Special RegularOperation
Special ::getter setter deleter
OperationRest ::OptionalOperationName ( ArgumentList ) ;
OptionalOperationName ::OperationName ε
OperationName ::OperationNameKeyword identifier
OperationNameKeyword ::includes
ArgumentList ::Argument Arguments ε
Arguments ::, Argument Arguments ε
Argument ::ExtendedAttributeList ArgumentRest
ArgumentRest ::optional TypeWithExtendedAttributes ArgumentName Default Type Ellipsis ArgumentName
ArgumentName ::ArgumentNameKeyword identifier
Ellipsis ::... ε
ArgumentNameKeyword ::async attribute callback const constructor deleter dictionary enum getter includes inherit interface iterable maplike mixin namespace partial readonly required setlike setter static stringifier typedef unrestricted
2.5.3.1. toJSON
通过声明一个 toJSON
常规操作,
一个 接口 指定了如何将实现它的对象转换为 JSON 类型。
toJSON
常规操作 保留用于此用途。
它必须不带参数并返回 JSON 类型。
JSON 类型包括:
toJSON
常规操作 在语言绑定中如何在对象上可用,以及 JSON 类型 如何精确地转换为 JSON 字符串,取决于具体的语言绑定。
注意:在 JavaScript 语言绑定中,这通过暴露一个 toJSON
方法来实现,
该方法返回转换为 JavaScript 值的 JSON
类型,
该值可以通过 JSON.stringify()
函数转化为 JSON 字符串。
此外,在 JavaScript 语言绑定中, toJSON
操作可以带有 [Default
] 扩展属性,
在这种情况下,默认的 toJSON
步骤 将被暴露。
以下 IDL 片段 定义了一个名为
Transaction
的接口,
它有一个以行文方式定义的 toJSON
方法:
[Exposed =Window ]interface Transaction {readonly attribute DOMString from ;readonly attribute DOMString to ;readonly attribute double amount ;readonly attribute DOMString description ;readonly attribute unsigned long number ;TransactionJSON toJSON (); };dictionary TransactionJSON {Account from ;Account to ;double amount ;DOMString description ; };
Transaction
接口 的
toJSON
常规操作 可以定义如下:
toJSON()
方法步骤如下:
在 JavaScript 语言绑定中, Transaction
对象上将存在一个 toJSON()
方法:
// 获取一个 Transaction 实例。 var txn= getTransaction(); // 结果评估为类似这样的对象: // { // from: "Bob", // to: "Alice", // amount: 50, // description: "books" // } txn. toJSON(); // 结果评估为类似这样的字符串: // '{"from":"Bob","to":"Alice","amount":50,"description":"books"}' JSON. stringify( txn);
2.5.4. 构造操作
如果一个 接口 具有 构造操作 成员(匹配
在一个 接口 上可以出现多个 构造操作。 对于该 接口 上的每个 构造操作,将有一种方式通过传递指定的参数来尝试构造实例。
名为 interface 的接口的构造操作的 构造步骤应使用如下形式的文本引入:“new interface(arg1,
arg2, ...)
构造步骤如下:”,然后跟一个列表,或者“new interface(arg1,
arg2, ...)
构造步骤是”后跟内联描述。
构造步骤必须不做任何操作,初始化作为 this 传递的值,或者抛出异常。
如果构造函数没有初始化 this,可以写作:“new Example(init)
构造步骤是不做任何操作。”
有关如何实现 构造操作 的详细信息,请参见 § 3.7.1 接口对象。
以下 IDL 定义了两个接口。第二个接口具有 构造操作,而第一个没有。
[Exposed =Window ]interface NodeList {Node item (unsigned long index );readonly attribute unsigned long length ; }; [Exposed =Window ]interface Circle {constructor ();constructor (double radius );attribute double r ;attribute double cx ;attribute double cy ;readonly attribute double circumference ; };
支持这些接口的 JavaScript 实现将在 Circle
接口对象上实现一个 [[Construct]] 内部方法,该方法将返回实现该接口的
新对象。它可以接受零个或一个参数。
目前尚不清楚 NodeList
接口对象是否会实现 [[Construct]] 内部方法。无论如何,尝试将其用作构造函数都会导致抛出
TypeError
。
[whatwg/webidl 问题 #698]
var x= new Circle(); // 这使用零参数构造函数创建了 // 一个实现 Circle 接口的平台对象的引用。 var y= new Circle( 1.25 ); // 这次使用一个参数构造函数创建了一个 Circle 对象。 var z= new NodeList(); // 这会抛出一个 TypeError,因为没有 // 声明构造函数。
Constructor ::constructor ( ArgumentList ) ;
Ellipsis ::... ε
ArgumentNameKeyword ::async attribute callback const constructor deleter dictionary enum getter includes inherit interface iterable maplike mixin namespace partial readonly required setlike setter static stringifier typedef unrestricted
2.5.5. 字符串化
当一个 接口 具有 stringifier 时,
这表示实现该接口的对象具有非默认的字符串转换。Stringifier 可以通过使用
interface interface_identifier {stringifier ; };
与接口相关的文本必须定义接口的 字符串化行为。
DOMString
或 USVString
。
它也不得放置在 静态属性 上。
interface interface_identifier {stringifier attribute DOMString identifier ; };
在给定的 接口 上,最多只能存在一个 stringifier。
Stringifier ::stringifier StringifierRest
StringifierRest ::OptionalReadOnly AttributeRest ;
以下 IDL 片段
定义了一个接口,该接口将字符串化为其
name
属性的值:
[Exposed =Window ]interface Student {constructor ();attribute unsigned long id ;stringifier attribute DOMString name ; };
在 JavaScript 绑定中,在需要字符串的上下文中使用 Student
对象将导致使用对象的
name
属性的值:
var s= new Student(); s. id= 12345678 ; s. name= '周杰倫' ; var greeting= 'Hello, ' + s+ '!' ; // 现在 greeting == 'Hello, 周杰倫!'。
以下 IDL 片段 定义了一个接口,该接口具有自定义字符串化行为,且 IDL 本身未指定。
[Exposed =Window ]interface Student {constructor ();attribute unsigned long id ;attribute DOMString ?familyName ;attribute DOMString givenName ;stringifier ; };
因此,需要有相应的文本来解释字符串化行为。
我们假设 familyName
和 givenName
属性分别由姓氏和名字概念支持。
字符串化行为 步骤如下:
IDL 的 JavaScript 实现行为如下:
var s= new Student(); s. id= 12345679 ; s. familyName= 'Smithee' ; s. givenName= 'Alan' ; var greeting= 'Hi ' + s; // 现在 greeting == 'Hi Alan Smithee'。
2.5.6. 特殊操作
特殊操作 是在实现接口的对象上声明某种特殊行为的声明,这些特殊操作声明出现在该接口上。通过在操作声明中使用 特殊关键字 来声明特殊操作。
特殊操作有三种类型。下表列出了给定的特殊操作类型所使用的特殊关键字以及该特殊操作的目的:
特殊操作 | 关键字 | 目的 |
---|---|---|
取值器 | 定义对象在进行属性检索时的行为。 | |
赋值器 | 定义对象在进行属性赋值或创建时的行为。 | |
删除器 | 定义对象在进行属性删除时的行为。 |
并非所有语言绑定都支持所有这四种特殊对象行为。当使用没有标识符的操作声明特殊操作时,在不支持这些特殊操作的语言绑定中,此类功能将不会被实现。
以下 IDL 片段定义了一个具有 getter 和 setter 的接口:
[Exposed =Window ]interface Dictionary {readonly attribute unsigned long propertyCount ;getter double (DOMString propertyName );setter undefined (DOMString propertyName ,double propertyValue ); };
在不支持属性 getter 和 setter 的语言绑定中,实现 Dictionary 的对象将不会具备该特殊行为。
定义一个带有 标识符 的特殊操作等同于将该特殊操作分离为独立的、没有标识符的声明。这种方法被允许简化接口操作的 方法步骤。
以下两个接口是等价的:
[Exposed =Window ]interface Dictionary {readonly attribute unsigned long propertyCount ;getter double getProperty (DOMString propertyName );setter undefined setProperty (DOMString propertyName ,double propertyValue ); };
[Exposed =Window ]interface Dictionary {readonly attribute unsigned long propertyCount ;double getProperty (DOMString propertyName );undefined setProperty (DOMString propertyName ,double propertyValue );getter double (DOMString propertyName );setter undefined (DOMString propertyName ,double propertyValue ); };
一个给定的 特殊关键字不能在一个操作上出现两次。
取值器和赋值器有两种类型:一种是使用 DOMString
作为属性名,称为 命名属性取值器 和 命名属性赋值器,另一种是使用 unsigned long
作为属性索引,称为 索引属性取值器 和 索引属性赋值器。删除器只有一种类型:命名属性删除器。详情请参阅 § 2.5.6.1 索引属性 和 § 2.5.6.2 命名属性。
在给定的 接口 上,最多只能有一个 命名属性删除器,以及每种类型的取值器和赋值器各一个。
如果一个接口具有某种类型的赋值器,则它必须也具有该类型的取值器。如果它具有 命名属性删除器,则它必须也具有 命名属性取值器。
使用操作声明的特殊操作不得是 可变参数,也不得有任何 可选参数。
如果一个对象实现了多个定义相同特殊操作的 接口,则无法确定将调用哪个(如果有的话)特殊操作。
2.5.6.1. 索引属性
定义了 索引属性取值器 的 接口 被认为 支持索引属性。 由此扩展,如果 平台对象 实现了 接口,则该对象被认为 支持索引属性。
如果一个接口 支持索引属性,那么该接口定义必须附带描述对象在任何给定时间可以使用哪些索引来进行索引操作的描述。这些索引称为 支持的属性索引。
支持索引属性的接口必须定义一个名为 "length
" 的 整数类型 属性。
索引属性取值器必须声明为接受一个 unsigned long
参数。 索引属性赋值器必须声明为接受两个参数,其中第一个参数是 unsigned long
。
interface interface_identifier {getter type identifier (unsigned long identifier );setter type identifier (unsigned long identifier ,type identifier );getter type (unsigned long identifier );setter type (unsigned long identifier ,type identifier ); };
以下要求适用于索引属性取值器和赋值器的定义:
-
如果通过带有 标识符 的 操作 指定了 索引属性取值器,则使用给定 支持的属性索引 对对象进行索引时返回的值应是调用该操作并传递该索引作为唯一参数的结果。如果用于声明索引属性取值器的操作没有标识符,则接口定义必须附带如何为给定索引 确定索引属性的值 的描述。
-
如果通过带有标识符的操作指定了 索引属性赋值器,则对对象进行属性赋值时的行为与调用该操作并传递索引作为第一个参数、值作为第二个参数时的行为相同。如果用于声明索引属性赋值器的操作没有标识符,则接口定义必须附带如何为给定属性索引和值 设置现有索引属性的值 以及如何 设置新索引属性的值 的描述。
请注意,如果使用带有标识符的 操作 指定了 索引属性取值器 或 赋值器,那么使用不是 支持的属性索引 的整数对对象进行索引时的行为不一定与使用该索引调用操作时的行为相同。在这种情况下的实际行为取决于具体的语言绑定。
在 JavaScript 语言绑定中,进行的是常规的属性查找。例如,以下 IDL:
[Exposed =Window ]interface A {getter DOMString toWord (unsigned long index ); };
假设实现 A
的对象在 0 ≤ index < 2 的范围内具有 支持的属性索引。还假设
toWord 定义为将其参数转换为英文单词。当使用超出范围的索引调用 操作 时的行为与直接对对象进行索引的行为不同:
var a= getA(); a. toWord( 0 ); // 返回 "zero". a[ 0 ]; // 也返回 "zero". a. toWord( 5 ); // 返回 "five". a[ 5 ]; // 返回 undefined,因为没有名为 "5" 的属性。
以下 IDL 片段定义了一个 OrderedMap
接口,该接口允许通过名称或索引号检索和设置值:
[Exposed =Window ]interface OrderedMap {readonly attribute unsigned long size ;getter any getByIndex (unsigned long index );setter undefined setByIndex (unsigned long index ,any value );getter any get (DOMString name );setter undefined set (DOMString name ,any value ); };
由于所有特殊操作都是通过带有标识符的操作声明的,因此唯一需要的附加说明是描述这些集合具有哪些键。假设 get()
操作定义为在尝试查找 OrderedMap
中不存在的条目时返回
实现
OrderedMap
的对象 map 支持范围为 0 ≤ index <map.size
的索引属性。此类对象还支持每个名称属性,对于这些名称,若将其传递给
get()
,将返回非空值。
如 § 3.9 传统平台对象 中所述,JavaScript 实现将在实现 OrderedMap
的 传统平台对象 上创建对应于命名和索引属性集的属性。这些属性可以像调用对象的方法一样与对象交互,如下所示:
// 假设 map 是一个实现了 OrderedMap 接口的传统平台对象。 var map= getOrderedMap(); var x, y; x= map[ 0 ]; // 如果 map.length > 0,则等效于: // // x = map.getByIndex(0) // // 因为一个名为 "0" 的属性将被添加到 map 上。 // 否则,x 将被设置为 undefined,因为 map 上没有名为 "0" 的属性。 map[ 1 ] = false ; // 这将等效于: // // map.setByIndex(1, false) y= map. apple; // 如果存在名为 "apple" 的属性,则这将等效于: // // y = map.get('apple') // // 因为一个名为 "apple" 的属性将被添加到 map 上。否则,y 将被设置为 undefined,因为 map 上没有名为 "apple" 的属性。 map. berry= 123 ; // 这将等效于: // // map.set('berry', 123) delete map. cake; // 如果存在名为 "cake" 的属性,则将删除 "cake" 属性,然后执行以下操作的等效操作: // // map.remove("cake")
2.5.6.2. 命名属性
定义了 命名属性 getter 的 接口 称为 支持命名属性。 拓展来说,实现了 接口 的 平台对象 也称为 支持命名属性。
如果一个接口 支持命名属性, 那么该接口的定义必须附带描述该对象在任何给定时间可用于索引的名称的有序集合。 这些名称称为 受支持的属性名称。
命名属性 getter 和 deleter 必须声明只接受一个 DOMString
参数。
命名属性 setter 必须声明接受两个参数,其中第一个是 DOMString
。
interface interface_identifier {getter type identifier (DOMString identifier );setter type identifier (DOMString identifier ,type identifier );deleter type identifier (DOMString identifier );getter type (DOMString identifier );setter type (DOMString identifier ,type identifier );deleter type (DOMString identifier ); };
以下要求适用于命名属性 getter、setter 和 deleter 的定义:
-
如果 命名属性 getter 是使用带有 标识符 的 操作 指定的, 那么当使用给定的 受支持的属性名称 对象进行索引时返回的值与调用操作返回的值相同,将名称作为其唯一参数传递。 如果用于声明命名属性 getter 的操作没有标识符,则接口定义必须附带描述如何为给定的属性名称 确定命名属性的值 的描述。
-
如果 命名属性 setter 是使用带有标识符的操作指定的, 那么当使用给定的受支持属性名称和值对对象进行索引以进行属性赋值时发生的行为与调用操作时相同,将名称作为第一个参数,将值作为第二个参数传递。 如果用于声明命名属性 setter 的操作没有标识符,则接口定义必须附带描述如何 设置现有命名属性的值 以及如何 为给定的属性名称和值 设置新命名属性的值。
-
如果 命名属性 deleter 是使用带有标识符的操作指定的, 那么当使用给定的受支持属性名称对对象进行索引以删除属性时发生的行为与调用操作时相同,将名称作为唯一参数传递。 如果用于声明命名属性 deleter 的操作没有标识符,则接口定义必须附带描述如何为给定的属性名称 删除现有命名属性。
注意:与 索引属性 类似, 如果 命名属性 getter、setter 或 deleter 是使用带有 标识符 的 操作 指定的, 那么使用不属于 受支持的属性名称 的名称对对象进行索引的行为不一定与调用该名称的操作时的行为相同;此行为是语言绑定特定的。
2.5.7. 静态属性和操作
静态属性
和 静态操作 是那些
不与声明其上的 接口
的特定实例相关联的,而是与接口本身相关联的属性和操作。静态属性和操作通过在声明中使用
是否可以通过接口实例的引用调用静态操作或获取或设置静态属性取决于语言绑定的具体实现。
StaticMember ::static StaticMemberRest
StaticMemberRest ::OptionalReadOnly AttributeRest RegularOperation
以下 IDL 片段
定义了一个具有静态操作的接口 Circle
:
[Exposed =Window ]interface Point { /* ... */ }; [Exposed =Window ]interface Circle {attribute double cx ;attribute double cy ;attribute double radius ;static readonly attribute long triangulationCount ;static Point triangulate (Circle c1 ,Circle c2 ,Circle c3 ); };
在 JavaScript 语言绑定中,函数对象 triangulate
和访问器属性
triangulationCount
将存在于 Circle
的
接口对象 上:
var circles= getCircles(); // Circle 对象的数组 typeof Circle. triangulate; // 计算结果为 "function" typeof Circle. triangulationCount; // 计算结果为 "number" Circle. prototype. triangulate; // 计算结果为 undefined Circle. prototype. triangulationCount; // 计算结果同样为 undefined circles[ 0 ]. triangulate; // 也是 undefined circles[ 0 ]. triangulationCount; // 也是 undefined // 调用静态操作 var triangulationPoint= Circle. triangulate( circles[ 0 ], circles[ 1 ], circles[ 2 ]); // 查找我们已经完成了多少次三角剖分 window. alert( Circle. triangulationCount);
2.5.8. 重载
如果一个定义在 接口 上的 常规操作 或 静态操作 的 标识符 与该接口上的其他同类操作(常规或静态)的标识符相同, 则该操作被称为 重载。 当使用重载操作的标识符调用实现该接口的对象上的操作时,传递给操作的参数数量和类型决定了实际调用的重载操作。 构造函数操作 也可以被重载。 对于重载操作和构造函数可以指定的参数有一些限制,为了描述这些限制,使用了“有效重载集”的概念。
一组重载的 操作 必须满足以下条件之一:
-
不包含任何返回类型为 promise 类型 的操作;
-
仅包含返回类型为 promise 类型 的操作。
操作 不能在 接口、部分接口、接口混入 和 部分接口混入 定义之间被重载。
例如,f 和 g 的重载都是不允许的:
[Exposed =Window ]interface A {undefined f (); };partial interface A {undefined f (double x );undefined g (); };partial interface A {undefined g (DOMString x ); };
注意,构造函数操作 和
[LegacyFactoryFunction
]
扩展属性
不允许出现在
部分接口定义中,
因此不需要另外禁止构造函数的重载。
一个 有效重载集
表示特定
操作、构造函数(由 构造函数操作 或 [LegacyFactoryFunction
] 指定)或
回调函数 的允许调用。
用于 计算有效重载集 的算法
针对以下四种 IDL 构造之一进行操作,下面列出的是计算集时需要的输入:
- 对于常规操作
- 对于静态操作
- 对于构造函数
- 对于遗留工厂函数
-
-
要查找 [
LegacyFactoryFunction
] 扩展属性的 接口 -
遗留工厂函数的 标识符
-
要传递的参数数量
-
一个有效的重载集用于确定在接口上指定的重载操作和构造函数是否存在歧义等。
有效重载集的项目是形式为 (可调用, 类型列表, 可选性列表) 的元组,其项目描述如下:
-
可调用项 是一个 操作,如果 有效重载集 是针对 常规操作、 静态操作,或 构造函数操作;如果是针对 遗留工厂函数 的 有效重载集,则为 扩展属性。
-
类型列表 是一个 IDL 类型的 列表。
-
可选性列表 是一个 列表,其包含三种可能的 可选性值 ——“必需的”、“可选的”或“可变参数的”, 指示在给定索引处的参数是被声明为 可选的,还是 对应于 可变参数。
每个 元组 代表操作、构造函数或回调函数的一个允许调用, 其参数值列表为给定类型。由于使用了 可选参数 和 可变参数 操作和构造函数,有效重载集 中可能有多个项标识相同的操作或构造函数。
-
操作或遗留工厂函数的标识符为 A
-
参数计数为 N
-
接口为 I
当提到扩展属性的参数时,它指的是扩展属性的 命名参数列表 中的一个参数。
-
令 S 为一个 有序集合。
-
令 F 为一个 有序集合,其中包含以下项, 根据 有效重载集 的种类:
- 对于常规操作
-
F 的元素是接口 I 上具有标识符 A 的 常规操作。
- 对于静态操作
-
F 的元素是接口 I 上具有标识符 A 的 静态操作。
- 对于构造函数
-
F 的元素是接口 I 上的 构造函数操作。
- 对于遗留工厂函数
-
F 的元素是接口 I 上的带有 [
LegacyFactoryFunction
] 扩展属性,其命名参数列表的标识符为 A。
-
令 maxarg 为 F 中操作、遗留工厂函数或回调函数声明的最大参数数。 对于 可变参数 的操作和遗留工厂函数, 省略号出现的参数计为一个参数。
注意:因此
undefined f(long x, long... y);
被认为声明了两个参数。 -
令 max 为 max(maxarg, N)。
-
对每个 F 中的操作或扩展属性 X:
-
返回 S。
对于以下接口:
[Exposed =Window ]interface A { /* f1 */undefined f (DOMString a ); /* f2 */undefined f (Node a ,DOMString b ,double ...c ); /* f3 */undefined f (); /* f4 */undefined f (Event a ,DOMString b ,optional DOMString c ,double ...d ); };
假设 Node
和 Event
是两个接口,且没有对象可以同时实现这两个接口,有效重载集中与标识符 f
和参数数量 4 对应的常规操作为:
« (f1, « DOMString », « required »), (f2, « Node, DOMString », « required, required »), (f2, « Node, DOMString, double », « required, required, variadic »), (f2, « Node, DOMString, double, double », « required, required, variadic, variadic »), (f3, « », « »), (f4, « Event, DOMString », « required, required »), (f4, « Event, DOMString, DOMString », « required, required, optional »), (f4, « Event, DOMString, DOMString, double », « required, required, optional, variadic ») »
两个类型在以下算法返回 true 时被认为是可区分的。
-
如果一个类型包含一个可空类型,另一个类型也包含一个可空类型,是一个联合类型,且展平后的成员类型包含字典类型,或者是字典类型,则返回false。
-
如果一个类型是联合类型或可空联合类型,返回 true,如果联合类型的每个成员类型与非联合类型相互可区分,否则返回 false。
-
考虑两个类型的“最内层”类型,通过获取每个类型的内部类型,如果它是注释类型,然后获取它的内部类型,如果结果是可空类型。如果这两个最内层类型出现在下表中,且在相应条目中有“●”标记,或者有字母且满足下表的附加要求,则返回true,否则返回false。
类别:
undefinedbooleannumeric typesbigintstring typesobjectsymbolinterface-likecallback functiondictionary-likeasync iterablesequence-likeundefined ● ● ● ● ● ● ● ● ● ● boolean ● ● ● ● ● ● ● ● ● ● numeric types (b) ● ● ● ● ● ● ● ● bigint ● ● ● ● ● ● ● ● string types ● ● ● ● ● (d) ● object ● symbol ● ● ● ● ● interface-like (a) ● ● ● ● callback function (c) ● ● dictionary-like ● ● async iterable sequence-like -
两个标识的接口类型不同,且没有单一平台对象同时实现这两种接口类型。
-
这些类型是可区分的,但对其在重载中的使用有额外限制。另请注意关于使用这些类型联合的建议。
-
不具有 [
LegacyTreatNonObjectAsNull
] 扩展属性的回调函数可与字典类类别中的类型区分开。 -
这些类型是可区分的,但是在从 ECMAScript 值转换时,如果字符串类型也在重载集或联合中,则字符串对象永远不会转换成异步可迭代类型(即使它具有
%Symbol.iterator%
方法)。
给定:callback interface CBIface {undefined handle (); }; [Exposed =Window ]interface Iface {attribute DOMString attr2 ; };dictionary Dict {DOMString field1 ; };CBIface
可与Iface
区分开,因为字典类型和接口类型的交叉处有 ●,但不能与Dict
区分,因为字典类型与自身的交叉处没有 ●。Promise 类型没有出现在上表中,因此它不能与任何其他类型区分。 -
如果在一个有效重载集中有多个具有相同类型列表 大小的项目,那么对于这些项目,必须存在一个索引i,使得每对项目在索引i处的类型是可区分的。该最小索引被称为区分参数索引,用于具有给定类型列表大小的有效重载集中的项目。
一个有效重载集中不得包含多个具有相同类型列表 大小的项目,其中一个项目在区分参数索引处有一个bigint
参数,而另一个项目在该索引处有一个数字类型参数。
考虑在之前示例中显示的有效重载集合。该集合中包含多个具有类型列表大小为2、3和4的项。对于每个类型列表大小,区分参数索引为0,因为Node
和Event
是可区分的。
但是,以下重载的使用是无效的:
[Exposed =Window ]interface B {undefined f (DOMString x );undefined f (USVString x ); };
此外,对于每个索引j,如果j小于给定类型列表大小的区分参数索引,那么所有项的类型列表中索引j处的类型必须相同,且所有项的可选性列表中索引j处的可选性值也必须相同。
以下是无效的:
[Exposed =Window ]interface B { /* f1 */undefined f (DOMString w ); /* f2 */undefined f (long w ,double x ,Node y ,Node z ); /* f3 */undefined f (double w ,double x ,DOMString y ,Node z ); };
对于参数数量为4的情况,有效重载集合为:
« (f1, « DOMString », « required »), (f2, « long, double, Node, Node », « required, required, required, required »), (f3, « double, double, DOMString, Node », « required, required, required, required ») »
查看类型列表大小为4的项,区分参数索引为2,因为Node
和DOMString
是可区分的。然而,由于这两个重载在索引0处的参数不同,因此此重载是无效的。
2.5.8.1. 重载与联合类型
本节是说明性的。
对于定义IDL 操作的规范来说,重载和 联合类型以及 可选参数之间似乎有一些功能重叠。
首先需要注意的是,重载与联合类型或可选参数的行为不同,并且一个不能完全用另一个来定义(当然,除非提供了额外的说明文字,但这可能会违背
Web IDL 类型系统的目的)。
例如,考虑在 CanvasDrawPath
接口[HTML]上定义的 stroke()
操作:
interface CanvasDrawPathExcerpt {undefined stroke ();undefined stroke (Path2D path ); };
根据JavaScript语言绑定,调用stroke(undefined)
会尝试调用第二个重载,导致抛出
TypeError
,因为Path2D
。
然而,如果操作改为定义为具有可选参数并合并为一个操作,
interface CanvasDrawPathExcerptOptional {undefined stroke (optional Path2D path ); };
则重载解析算法将会将path参数视为缺失, 并不会抛出任何异常。
注意: 在这个特定的例子中,后者的行为实际上更符合Web开发人员的预期。
如果今天设计CanvasDrawPath
,将会为stroke()
使用可选参数。
此外,还有语义上的差异。联合类型通常用于"任何类型都可以以大致相同的方式工作"的场景。 相比之下,重载 操作旨在更好地映射到C++等语言特性,并且通常更适合根据不同参数类型执行实质性不同操作的情况。 然而,在大多数情况下,具有如此实质性差异的操作最好使用不同的名称,以避免Web开发人员的混淆, 因为JavaScript语言不提供语言级的重载。因此,重载很少适用于新的API,而通常出现在旧的API或特殊情况下。
尽管如此,我们仍提供以下建议和示例,以供在决定使用哪种Web IDL语言特性时遇到困难时参考:
-
在一种不常见的情况下,操作需要根据不同的参数类型返回不同类型的值,重载将会使IDL片段更加富有表达力。 这种情况几乎从来不是合适的API设计,具有不同名称的单独操作通常是更好的选择。
假设有一个
calculate()
操作,它接受long
、DOMString
,或者CalculatableInterface
(一种接口类型)作为唯一的参数,并返回与参数类型相同类型的值。 使用重载操作写这个IDL片段会比使用 联合类型与typedef更清晰,如下所示:interface A {long calculate (long input );DOMString calculate (DOMString input );CalculatableInterface calculate (CalculatableInterface input ); };比起使用联合类型和typedef如下:
typedef (long or DOMString or CalculatableInterface )Calculatable ;interface A {Calculatable calculate (Calculatable input ); };后者并没有传达出返回值始终与input类型一致的事实。
如果指定的
calculate()
是一个新API且没有兼容性问题,建议为重载操作使用不同的名称,例如:interface A {long calculateNumber (long input );DOMString calculateString (DOMString input );CalculatableInterface calculateCalculatableInterface (CalculatableInterface input ); };这样可以让Web开发者编写明确而不含糊的代码。
-
当操作对于不同的参数类型或长度有显著不同的语义时,重载是首选。再次强调,在这种情况下,通常最好为不同的操作创建不同的名称, 但旧API有时遵循这种模式。
例如,
supports(property, value)
和supports(conditionText)
操作的CSS
接口是通过以下IDL片段定义的:[CSS3-CONDITIONAL] [CSSOM]。partial interface CSS {static boolean supports (CSSOMString property ,CSSOMString value );static boolean supports (CSSOMString conditionText ); };使用可选参数可以重写这个IDL片段,如下所示:
partial interface CSSExcerptOptional {static boolean supports (CSSOMString propertyOrConditionText ,optional CSSOMString value ); };虽然第二个版本的IDL更短,但第一个参数中的两个截然不同的概念被混淆了。 如果没有重载, 要回答"是property还是conditionText与value配对?"的问题就会变得更加困难, 需要阅读操作的方法步骤。 这使得第二个版本比第一个版本显著难以理解。
另一个需要考虑的因素是,方法步骤可以为 重载操作指定不同的块, 这有助于规范的阅读和编写。而可选参数 则不具备这一特性。这意味着在第一种情况下,规范作者可以像这样编写操作的 方法步骤:
方法
supports(property, value)
的步骤是:-
…
方法
supports(conditionText)
的步骤是:-
…
然而,使用value作为可选参数, 规范作者必须使用更多的样板式文本来有效地复制 重载解析算法。
方法
supports(propertyOrConditionText, value)
的步骤是:-
如果给定value,则:
-
让property为propertyOrConditionText。
-
…
-
-
否则:
-
让conditionText为propertyOrConditionText。
-
…
-
如果两个重载共享的部分很少,最好让IDL机制处理重载解析。
-
-
如果操作接受多个参数类型且不同参数类型之间没有关联,联合类型有时可能是唯一可行的解决方案。
typedef (long long or DOMString or CalculatableInterface )SupportedArgument ;interface A {undefined add (SupportedArgument operand1 ,SupportedArgument operand2 ); };对于上面的
add()
操作,使用重载来指定它将需要:interface A {undefined add (long long operand1 ,long long operand2 );undefined add (long long operand1 ,DOMString operand2 );undefined add (long long operand1 ,CalculatableInterface operand2 );undefined add (DOMString operand1 ,long long operand2 );undefined add (DOMString operand1 ,DOMString operand2 );undefined add (DOMString operand1 ,CalculatableInterface operand2 );undefined add (CalculatableInterface operand1 ,long long operand2 );undefined add (CalculatableInterface operand1 ,DOMString operand2 );undefined add (CalculatableInterface operand1 ,CalculatableInterface operand2 ); };以及对应的九倍的文本!
-
规范作者应鼓励在JavaScript语言绑定中将缺失参数和
undefined 参数以相同方式处理。给定以下IDL片段:
interface A {undefined foo ();undefined foo (Node ?arg ); };在JavaScript语言绑定中,调用
foo(undefined)
和foo(null)
都将执行与foo(arg)
操作相应的步骤,并将arg设置为null, 而单独调用foo()
则会进入第一个重载。这对于许多API用户来说可能是意外的行为。 因此,规范作者应鼓励使用可选参数, 这将把foo()
和foo(undefined)
都视为"arg缺失"。interface A {undefined foo (optional Node ?arg ); };通常,可选性最好通过
optional 关键字来表达,而不是使用重载。
当情况不符合上述任何类别时,规范作者可以自行选择样式,因为很可能任何一种样式都能充分且方便地描述预期的行为。然而,联合类型和可选参数的定义与转换算法比重载解决算法更容易实现和推理,并且通常会在JavaScript语言绑定中生成更符合惯用法的API。因此,除非有其他考虑,联合类型、可选参数或两者都是默认选择。
如果作者认为合适且方便,规范也可以自由混合使用联合类型和重载。
2.5.9. 可迭代声明
一个接口可以通过在接口主体中使用一个可迭代声明(匹配
interface interface_identifier {iterable <value_type >;iterable <key_type ,value_type >; };
实现了声明为可迭代接口的对象支持通过迭代获取一系列值。
注意:在JavaScript语言绑定中,一个可迭代的接口将在其接口原型对象上拥有entries
、forEach
、keys
、values
,以及%Symbol.iterator%
属性。
如果给出了一个类型参数,则该接口将拥有一个值迭代器并提供指定类型的值。如果给出了两个类型参数,则该接口将拥有一个对迭代器并提供具有给定类型的值对。
给定一个键类型和一个值类型,一个值对是一个包含两个项的结构:
一个值迭代器只能在支持索引属性的接口上声明。值迭代器的值类型必须与索引属性获取器返回的类型相同。值迭代器被隐式定义为迭代对象的索引属性。
具有键值对迭代器的接口的相关文本必须为每个接口实例定义一个列表,该列表是该实例的值对,即迭代的值对列表。
为值迭代器生成的JavaScript forEach方法的回调调用类似于Array.prototype.forEach,而对迭代器的forEach方法的回调调用则类似于Map.prototype.forEach。
由于值迭代器目前仅允许在支持索引属性的接口上使用,因此使用类似于Array的forEach方法是合理的。可能会需要在(a)不支持索引属性的接口上,或者(b)带有一个回调类似于Set.prototype.forEach(其中键与值相同)的forEach方法上使用值迭代器。如果你正在创建需要这种forEach方法的API,请提交问题。
注意:这是数组迭代器对象的工作方式。对于支持索引属性的接口,entries
、keys
、values
和%Symbol.iterator%
返回的迭代器对象是真正的数组迭代器对象。
带有可迭代声明的接口必须不能有名为entries
、forEach
、keys
或values
的属性、常量或常规操作,也不能从拥有这些名称的属性、常量或常规操作的继承接口继承这些名称。
考虑以下接口SessionManager
,它允许通过用户名访问多个Session
对象:
[Exposed =Window ]interface SessionManager {Session getSessionForUser (DOMString username );iterable <DOMString ,Session >; }; [Exposed =Window ]interface Session {readonly attribute DOMString username ; // ... };
迭代器的行为可以这样定义:
要迭代的值对是由用户名为键,值为与该用户名对应的
SessionManager
对象上的打开的Session
对象组成的值对列表,按用户名排序。
在JavaScript语言绑定中,接口原型对象为SessionManager
接口提供了一个values
方法,该方法是一个函数,当调用时返回一个迭代器对象,该对象本身具有next
方法,返回下一个要迭代的值。它还提供了keys
和entries
方法,分别用于迭代会话对象的用户名和用户名/Session
对象对。还提供了一个%Symbol.iterator%
方法,允许SessionManager
在for..of
循环中使用,该方法的返回值与entries
方法相同:
// 获取一个SessionManager实例。 // 假设它有两个用户的会话,"anna"和"brian"。 var sm= getSessionManager(); typeof SessionManager. prototype. values; // 计算结果为 "function" var it= sm. values(); // values() 返回一个迭代器对象 String( it); // 计算结果为 "[object SessionManager Iterator]" typeof it. next; // 计算结果为 "function" // 该循环将首先记录"anna",然后是"brian"。 for (;;) { let result= it. next(); if ( result. done) { break ; } let session= result. value; console. log( session. username); } // 该循环也将记录"anna"和"brian"。 for ( let usernameof sm. keys()) { console. log( username); } // 另一种实现相同目标的方式。 for ( let [ username, session] of sm) { console. log( username); }
一个接口不能有多个可迭代声明。一个具有可迭代声明的接口及其继承的接口不能有maplike声明、setlike声明或异步可迭代声明。
以下扩展属性适用于可迭代声明: [CrossOriginIsolated
]、
[Exposed
] 和
[SecureContext
]。
Iterable ::iterable < TypeWithExtendedAttributes OptionalType > ;
OptionalType ::, TypeWithExtendedAttributes ε
2.5.10. 异步可迭代声明
一个接口可以通过在接口的主体中使用异步可迭代声明(匹配
interface interface_identifier {async iterable <value_type >;async iterable <value_type >(/* 参数... */);async iterable <key_type ,value_type >;async iterable <key_type ,value_type >(/* 参数... */); };
实现了声明为异步可迭代的接口的对象支持通过异步迭代来获取值序列。
如果只给出一个类型参数,则该接口具有值异步可迭代声明,并异步提供指定类型的值。如果给出了两个类型参数,则该接口具有键值对异步可迭代声明,并异步提供具有给定类型的键值对。
如果给定,异步可迭代声明的参数
(匹配
%Symbol.asyncIterator%
和 values
属性。如果该接口具有成对异步可迭代声明,它还将具有 entries
和 keys
属性。所有这些方法都可以传递可选参数,这些参数对应于异步可迭代声明中的参数列表,并由异步迭代器初始化步骤(如果存在)处理。
考虑到这一点,所有参数都必须是可选的这一要求确保了在 JavaScript 绑定中,for
-await
-of
可以直接作用于接口的实例,因为 for
-await
-of
会在不带参数的情况下调用 %Symbol.asyncIterator%
方法。
与具有接口和异步可迭代声明相关的描述性文字必须定义一个获取下一个迭代结果的算法。
该算法接收正在被迭代的接口的实例,以及异步迭代器本身(这有助于存储状态)。
它必须返回一个Promise
,该Promise要么被拒绝,要么解决为一个特殊的迭代结束值,以表示迭代的结束,或者解决为以下之一:
- 对于值异步可迭代声明:
-
一个声明中给定类型的值;
- 对于键值对异步可迭代声明:
-
一个包含声明中第一个给定类型的值和第二个给定类型的值的元组。
描述性文字还可以定义一个异步迭代器返回算法。该算法接收被迭代的接口的实例、异步迭代器本身,以及一个类型为any
的单一参数值。在异步迭代器的提前终止情况下,调用该算法。该算法必须返回一个Promise
;如果Promise兑现,兑现值将被忽略,但如果被拒绝,该失败将传递给异步迭代器API的使用者。
在JavaScript绑定中,该算法允许自定义当异步迭代器的return()
方法被调用时的行为。这通常发生在break
或return
语句导致退出for
-await
-of
循环时。
我们可以为throw()
添加一个类似的钩子。目前还没有这样的需求,但如果您在创建需要此类功能的API,请提交一个问题。
描述性文字还可以定义异步迭代器初始化步骤。这些步骤接收被迭代的接口的实例、新创建的迭代器对象,以及一个包含传递的参数(如果有的话)的IDL值列表。
具有 异步可迭代声明的接口不应具有任何名为entries
、keys
或values
的属性,常量,或常规操作,也不能具有任何继承了这些名称的继承接口。
考虑以下接口SessionManager
,它允许按用户名访问多个Session
对象:
[Exposed =Window ]interface SessionManager {Session getSessionForUser (DOMString username );async iterable <DOMString ,Session >; }; [Exposed =Window ]interface Session {readonly attribute DOMString username ; // ... };
迭代器的行为可以如下定义:
SessionManager
异步迭代器iterator的异步迭代器初始化步骤为:
将iterator的当前状态设置为“尚未开始”。
要为
SessionManager
manager及其异步迭代器iterator获取下一个迭代结果:
在JavaScript语言绑定中,接口原型对象中的SessionManager
接口具有一个values
方法,当调用时,它返回一个异步迭代器对象,该对象具有next
方法,该方法返回下一个迭代的值。它还有keys
和entries
方法,分别迭代会话对象的用户名和(用户名,Session
)对象对。它还具有一个%Symbol.asyncIterator%
方法,允许在for await..of
循环中使用SessionManager
,该循环返回与entries
方法相同的值:
// 获取SessionManager的实例。 // 假设它有两个用户的会话:"anna"和"brian"。 var sm= getSessionManager(); typeof SessionManager. prototype. values; // 计算结果为 "function" var it= sm. values(); // values() 返回一个迭代器对象 typeof it. next; // 计算结果为 "function" // 此循环将打印 "anna" 和 "brian"。 for await ( let usernameof sm. keys()) { console. log( username); } // 另一种实现相同功能的方式。 for await ( let [ username, session] of sm) { console. log( username); }
接口不能有多个异步可迭代声明。带有继承接口的接口不能同时具有异步可迭代声明。具有异步可迭代声明的接口及其继承接口不得具有类映射声明、类集合声明或可迭代声明。
以下扩展属性适用于异步可迭代声明:[CrossOriginIsolated
]、[Exposed
]和[SecureContext
]。
这些扩展属性目前尚未生效。当它们生效时,其效果将符合预期。
AsyncIterable ::async iterable < TypeWithExtendedAttributes OptionalType > OptionalArgumentList ;
OptionalArgumentList ::( ArgumentList ) ε
2.5.11. Maplike 声明
一个 接口 可以通过在接口主体中使用
maplike 声明
(匹配
interface interface_identifier {readonly maplike <key_type ,value_type >;maplike <key_type ,value_type >; };
实现了类映射声明的接口的对象表示有序映射的键值对,初始为空,称为该对象的映射条目。 键和值的类型在类映射声明的尖括号中给出。键必须是唯一的。
规范作者可以修改映射条目的内容,这将在JavaScript代码中自动反映对象的内容。
类映射接口支持适用于语言绑定的查询映射条目的API。如果未使用
注意:在JavaScript语言绑定中,用于操作映射条目的API类似于JavaScript Map
对象的API。如果使用了entries
、forEach
、get
、has
、keys
、values
、%Symbol.iterator%
方法以及size
属性获取器。对于可读写的类映射,还包括clear
、delete
和set
方法。
类映射接口不能有名为entries
、forEach
、get
、has
、keys
、size
或values
的属性、常量或常规操作,也不能具有任何具有这些名称的继承接口。
可读写的类映射接口不能有名为clear
、delete
或set
的属性或常量,也不能有任何具有这些名称的继承接口。
注意:可读写的类映射接口可以有名为clear
、delete
或set
的常规操作,这些操作将覆盖这些方法的默认实现(定义在§ 3.7.11 类映射声明中)。如果定义了这样的常规操作,它们必须匹配各方法的输入和输出期望,定义在各自的默认实现部分中。
接口不能有多个类映射声明。 类映射接口的继承接口不能也有类映射声明。 类映射接口及其继承接口不得具有可迭代声明、异步可迭代声明、类集合声明或索引属性获取器。
ReadOnlyMember ::readonly ReadOnlyMemberRest
ReadWriteMaplike ::MaplikeRest
MaplikeRest ::maplike < TypeWithExtendedAttributes , TypeWithExtendedAttributes > ;
添加示例。
2.5.12. Setlike 声明
一个 接口 可以通过在接口主体中使用
setlike 声明
(匹配
interface interface_identifier {readonly setlike <type >;setlike <type >; };
实现了类集合声明的接口的对象表示有序集合的值,初始为空,称为该对象的集合条目。 类集合声明的尖括号中给出了值的类型。值必须是唯一的。
规范作者可以修改集合条目的内容,这将在JavaScript代码中自动反映对象的内容。
类集合接口支持适用于语言绑定的查询集合条目的API。如果未使用
注意:在JavaScript语言绑定中,用于操作集合条目的API类似于JavaScript Set
对象的API。如果使用了entries
、forEach
、has
、keys
、values
、%Symbol.iterator%
方法以及size
属性获取器。对于可读写的类集合,还包括add
、clear
和delete
方法。
类集合接口不能有名为entries
、forEach
、has
、keys
、size
或values
的属性、常量或常规操作,也不能具有任何具有这些名称的继承接口。
可读写的类集合接口不能有名为add
、clear
或delete
的属性或常量,也不能有任何具有这些名称的继承接口。
注意:可读写的类集合接口可以有名为add
、clear
或delete
的常规操作,这些操作将覆盖这些方法的默认实现(定义在§ 3.7.12 类集合声明中)。如果定义了这样的常规操作,它们必须匹配各方法的输入和输出期望,定义在各自的默认实现部分中。
接口不能有多个类集合声明。 类集合接口的继承接口不能也有类集合声明。 类集合接口及其继承接口不得具有可迭代声明、异步可迭代声明、类映射声明或索引属性获取器。
ReadOnlyMember ::readonly ReadOnlyMemberRest
ReadWriteSetlike ::SetlikeRest
SetlikeRest ::setlike < TypeWithExtendedAttributes > ;
添加示例。
2.6. 命名空间
命名空间是一个声明全局单例及其相关行为的定义(匹配
namespace identifier { /* namespace_members... */ };
命名空间是常规操作、只读 常规属性和常量的集合规范(匹配
与接口一样,命名空间的IDL可以通过使用部分命名空间定义(匹配
namespace SomeNamespace { /* namespace_members... */ };partial namespace SomeNamespace { /* namespace_members... */ };
注意:与部分接口定义一样,部分命名空间定义旨在作为规范编辑的辅助工具,允许命名空间定义分散在文档的多个部分,有时甚至是多个文档。
成员出现的顺序对于JavaScript绑定中的属性枚举具有重要意义。
注意,与接口或字典不同,命名空间不会创建类型。
在本规范中定义的扩展属性中,只有[CrossOriginIsolated
]、[Exposed
]和[SecureContext
]扩展属性适用于命名空间。
Partial ::partial PartialDefinition
Namespace ::namespace identifier { NamespaceMembers } ;
NamespaceMembers ::ExtendedAttributeList NamespaceMember NamespaceMembers ε
NamespaceMember ::RegularOperation readonly AttributeRest Const
namespace VectorUtils {readonly attribute Vector unit ;double dotProduct (Vector x ,Vector y );Vector crossProduct (Vector x ,Vector y ); };
JavaScript实现将公开一个全局VectorUtils
数据属性,它是一个简单的对象(原型为%Object.prototype%
),其中每个声明的操作都是可枚举的数据属性,每个声明的属性都是可枚举的只读访问器:
Object. getPrototypeOf( VectorUtils); // 计算结果为Object.prototype。 Object. keys( VectorUtils); // 计算结果为["dotProduct", "crossProduct"]。 Object. getOwnPropertyDescriptor( VectorUtils, "dotProduct" ); // 计算结果为{ value: <a function>, enumerable: true, configurable: true, writable: true }。 Object. getOwnPropertyDescriptor( VectorUtils, "unit" ); // 计算结果为{ get: <a function>, enumerable: true, configurable: true }。
2.7. 字典
字典是一种定义(匹配
dictionary identifier { /* dictionary_members... */ };
字典实例不会保留对其语言特定表示(例如,对应的JavaScript对象)的引用。因此,例如,从操作返回字典将从字典的当前值创建一个新的JavaScript对象,并且,接受字典作为参数的操作将基于当前的JavaScript对象属性进行一次性转换。对字典的修改不会反映在对应的JavaScript对象中,反之亦然。
字典可以定义为从另一个字典继承。如果字典的标识符后面跟着冒号和标识符,则该标识符标识继承的字典。标识符必须标识一个字典。
字典不能声明为使其继承层次结构产生循环。也就是说,字典A不能继承自自身,也不能继承自另一个继承自A的字典B,等等。
dictionary Base { /* dictionary_members... */ };dictionary Derived :Base { /* dictionary_members... */ };
给定字典D的继承字典是所有直接或间接从D继承的字典的集合。如果D没有从另一个字典继承,则该集合为空。否则,集合包括D继承自的字典E及其所有的继承字典。
字典成员可以指定为必需,这意味着将语言特定的值转换为字典时,必须为该成员提供值。任何未被指定为必需的字典成员都是可选的。
请注意,将字典成员指定为必需仅在将其他表示形式的字典(如作为操作参数提供的JavaScript值)转换为IDL字典时具有可观察的效果。在所有其他情况下,包括字典类型仅作为操作的返回类型时,规范作者应将成员保留为可选。
类型为D的字典值可以具有D定义的每个字典成员和D的任何继承字典中的字典成员的条目。指定为必需的字典成员,或指定为具有默认值的字典成员,将始终具有相应的条目。其他成员的条目可能存在,也可能不存在于字典值中。
在JavaScript绑定中,属性对应的字典成员的值为
与操作参数默认值一样,强烈建议不要使用boolean
类型字典成员的默认值,因为这可能会让作者感到困惑,他们可能期望使用默认的
具有字符串键的有序映射可以隐式视为特定字典D的字典值,如果其所有条目都对应于字典成员,并且这些条目具有正确的类型,并且存在针对任何必需或默认的字典成员的条目。
dictionary Descriptor {DOMString name ;sequence <unsigned long >serviceIdentifiers ; };
可以按照以下步骤创建Descriptor
字典:
-
让identifiers为« 1, 3, 7 »。
-
返回«[ "name" → "test", "serviceIdentifiers" → identifiers ]»。
每个字典成员(匹配
如果字典成员的类型在解析类型定义后是可空类型,则其内部类型不得是字典类型。
dictionary identifier {type identifier ; };
如果可选字典成员的标识符后面跟着U+003D (=)和一个值(匹配
dictionary identifier {type identifier = "value"; };
当布尔文字标记(
如果字典成员的类型是枚举,那么它的默认值(如果指定)必须是该枚举值之一。
如果字典成员的类型前有
dictionary identifier {required type identifier ; };
字典成员的类型不能包含它所在的字典。如果类型包含字典D,则至少满足以下条件之一:
-
类型是D
-
类型是从D继承的字典
-
类型是字典,其成员或继承成员的类型包含D
-
类型是
record<K, V>
,其中V包含D
与接口类似,字典的IDL可以通过使用部分字典定义(匹配
dictionary SomeDictionary { /* dictionary_members... */ };partial dictionary SomeDictionary { /* dictionary_members... */ };
注意:与部分接口定义类似,部分字典定义用于作为规范编辑的辅助工具,允许将字典的定义分散在文档的多个部分,有时甚至是多个文档中。
在给定字典中的字典成员的顺序是继承的字典成员排在非继承成员之前,并且字典定义(包括任何部分字典定义)中的字典成员按组成其标识符的Unicode代码点的字典顺序排列。
例如,以下定义:
dictionary B :A {long b ;long a ; };dictionary A {long c ;long g ; };dictionary C :B {long e ;long f ; };partial dictionary A {long h ;long d ; };
类型C
的字典值的字典成员的顺序是c、d、g、h、a、b、e、f。
字典需要有其成员的顺序,因为在某些语言绑定中,传递字典值给平台对象时观察到的行为取决于提取字典成员的顺序。例如,考虑以下附加接口:
[Exposed =Window ]interface Something {undefined f (A a ); };
以及以下JavaScript代码:
var something= getSomething(); // Get an instance of Something. var x= 0 ; var dict= { }; Object. defineProperty( dict, "d" , { get: function () { return ++ x; } }); Object. defineProperty( dict, "c" , { get: function () { return ++ x; } }); something. f( dict);
提取字典成员的顺序决定了它们将被认为具有的值。由于A
的顺序定义为先c再d,所以c的值将为1,而d的值将为2。
字典成员的标识符不能与字典中定义的另一个字典成员或该字典的继承字典中的字典成员相同。
没有扩展属性适用于字典。
Partial ::partial PartialDefinition
Dictionary ::dictionary identifier Inheritance { DictionaryMembers } ;
DictionaryMembers ::DictionaryMember DictionaryMembers ε
DictionaryMember ::ExtendedAttributeList DictionaryMemberRest
DictionaryMemberRest ::required TypeWithExtendedAttributes identifier ; Type identifier Default ;
PartialDictionary ::dictionary identifier { DictionaryMembers } ;
Default ::= DefaultValue ε
DefaultValue ::ConstValue string [ ] { } null undefined
Inheritance ::: identifier ε
字典类型的一个用途是允许操作拥有多个可选参数,而不必在调用时受限于指定它们的顺序。例如,考虑以下IDL片段:
[Exposed =Window ]interface Point {constructor ();attribute double x ;attribute double y ; };dictionary PaintOptions {DOMString fillPattern = "black";DOMString strokePattern ;Point position ; }; [Exposed =Window ]interface GraphicsContext {undefined drawRectangle (double width ,double height ,optional PaintOptions options ); };
在IDL的JavaScript实现中,可以为可选的PaintOptions
字典传入一个对象:
// 获取GraphicsContext的实例。 var ctx= getGraphicsContext(); // 画一个矩形。 ctx. drawRectangle( 300 , 200 , { fillPattern: "red" , position: new Point( 10 , 10 ) });
PaintOptions
的成员是可选的。如果省略了fillPattern
,drawRectangle
的定义可以假定它具有给定的默认值,而无需包含显式处理其省略的措辞。drawRectangle
需要显式处理省略strokePattern
和position
的情况。
2.8. 异常
异常是一种表示错误的对象类型,能够被抛出或作为一等值处理。Web IDL
预定义了一些异常类型,这些异常类型可以在规范定义的操作、属性等中引用并抛出。也可以自定义异常类型,作为继承自DOMException
的接口来定义。
简单异常可以通过以下类型之一标识:
-
EvalError
-
RangeError
-
ReferenceError
-
TypeError
-
URIError
这些对应于所有 JavaScript 错误对象
(除了 SyntaxError
和 Error
,它们被故意省略,
因为它们分别被保留给 JavaScript 解析器和作者使用)。每个 简单异常 的含义与其在 JavaScript 规范中的相应错误对象匹配。
第二种类型的异常是 DOMException
,
它通过提供一个 名称
来提供有关发生错误的进一步编程可检查的详细信息。
此类 名称 来自下方的 DOMException
名称表。
由于 DOMException
是一个 接口类型,
它可以在 IDL 中用作类型。这允许,例如,可以声明一个 操作 具有 DOMException
的
返回类型。然而,这通常是一个不好的模式,因为异常应当被抛出而不是返回。
最后一种类型的异常是 DOMException
的派生接口。
它们更复杂,因此在专门章节 § 2.8.2 DOMException 派生接口 中进行了描述。
简单异常
可以通过提供其类型名称进行 创建。
可以通过提供其 名称 后接 DOMException
来创建一个
DOMException
。
异常也可以通过提供创建所需的相同详细信息进行 抛出。
在这两种情况下,调用方可以提供关于异常指示内容的额外信息,这在构造异常的消息时非常有用。
以下是一些用于创建和抛出异常的措辞示例。要抛出一个新类型为TypeError
的简单异常:
要抛出一个带有名称NotAllowedError
的新DOMException
:
要创建一个带有名称SyntaxError
的新DOMException
:
让对象成为一个新
SyntaxError
的DOMException
。
要用名称OperationError
的新DOMException
来拒绝一个Promise:
拒绝p,并使用一个"OperationError
"DOMException
。
以下是包含构造异常消息时附加信息的示例:
抛出一个"SyntaxError
"DOMException
,表明给定的值包含不允许的尾随空格。
当异常抛出的原因不立即明显时,这类附加上下文对实现者非常有帮助,例如,当算法中的许多不同步骤都会抛出一个"SyntaxError
"DOMException
。相反,如果你的规范在检查用户是否提供了使用某个功能的权限之后立即抛出一个"NotAllowedError
"DOMException
,那么构造的消息应该很明显,因此无需明确说明。
创建和抛出异常的结果行为取决于语言绑定。
有关在JavaScript语言绑定中创建和抛出异常的详细信息,请参阅§ 3.14.3 创建和抛出异常。
2.8.1.
基础DOMException
错误名称
下面的DOMException
名称表列出了基础DOMException
接口实例的所有允许的名称,以及这些名称的含义和遗留的数字错误代码值。
继承自DOMException
的接口(如§ 2.8.2 DOMException派生接口中所述),将拥有自己的名称,未列入此表。
在创建或抛出一个DOMException
时,规范必须使用这些名称之一。如果规范作者认为这些名称都不适合其案例,他们必须提交问题,以讨论将新名称添加到共享命名空间,方便社区协调这些工作。请注意,只有当您认为Web开发人员会区分同一API产生的多个错误情况时,添加新的特定用途的名称才显得重要。
DOMException
名称标记为过时是为了兼容遗留问题,但不推荐使用这些名称。
注意:不要混淆这里定义的"SyntaxError
"DOMException
与JavaScript中的SyntaxError
。"SyntaxError
"DOMException
用于报告Web
API中的解析错误,例如解析选择器时,而JavaScript的SyntaxError
是为JavaScript解析器保留的。为了进一步避免混淆,请始终优先使用"SyntaxError
"DOMException
符号,而不是仅使用SyntaxError
来指代DOMException
。[DOM]
名称 | 描述 | 遗留代码名称和值 |
---|---|---|
"IndexSizeError " |
已废弃。 请使用RangeError 代替。
|
INDEX_SIZE_ERR (1) |
"HierarchyRequestError " |
该操作将导致一个错误的节点树。[DOM] | HIERARCHY_REQUEST_ERR (3)
|
"WrongDocumentError " |
该对象位于错误的文档中。[DOM] | WRONG_DOCUMENT_ERR (4) |
"InvalidCharacterError " |
字符串包含无效字符。 | INVALID_CHARACTER_ERR (5)
|
"NoModificationAllowedError " |
该对象无法被修改。 | NO_MODIFICATION_ALLOWED_ERR (7)
|
"NotFoundError " |
对象在此处找不到。 | NOT_FOUND_ERR (8)
|
"NotSupportedError " |
该操作不被支持。 | NOT_SUPPORTED_ERR (9) |
"InUseAttributeError " |
该属性正在被另一个元素使用。[DOM] | INUSE_ATTRIBUTE_ERR (10)
|
"InvalidStateError " |
对象处于无效状态。 | INVALID_STATE_ERR (11) |
"SyntaxError " |
字符串不符合预期的模式。 | SYNTAX_ERR (12) |
"InvalidModificationError " |
对象无法以这种方式修改。 | INVALID_MODIFICATION_ERR (13)
|
"NamespaceError " |
该操作不被XML命名空间允许。[XML-NAMES] | NAMESPACE_ERR (14) |
"InvalidAccessError " |
已废弃。 对于无效参数,请使用TypeError ;对于不支持的操作,请使用"NotSupportedError "DOMException ;对于被拒绝的请求,请使用"NotAllowedError "DOMException 。
|
INVALID_ACCESS_ERR (15)
|
"TypeMismatchError " |
已废弃。 请使用TypeError 代替。
|
TYPE_MISMATCH_ERR (17) |
"SecurityError " |
操作不安全。 | SECURITY_ERR (18)
|
"NetworkError " |
发生了网络错误。 | NETWORK_ERR (19)
|
"AbortError " |
操作已中止。 | ABORT_ERR (20) |
"URLMismatchError " |
已废弃。 | URL_MISMATCH_ERR (21) |
"QuotaExceededError " |
配额已超出。 | QUOTA_EXCEEDED_ERR (22)
|
"TimeoutError " |
操作超时。 | TIMEOUT_ERR (23)
|
"InvalidNodeTypeError " |
提供的节点不正确或具有错误的祖先节点。[DOM] | INVALID_NODE_TYPE_ERR (24)
|
"DataCloneError " |
对象无法克隆。 | DATA_CLONE_ERR (25) |
"EncodingError " |
编码操作(编码或解码)失败。 | — |
"NotReadableError " |
I/O 读取操作失败。 | — |
"UnknownError " |
由于未知的临时原因(例如内存不足),操作失败。 | — |
"ConstraintError " |
事务中的变更操作因未满足约束条件而失败。[INDEXEDDB] | — |
"DataError " |
提供的数据不足。 | — |
"TransactionInactiveError " |
对当前未激活或已完成的事务发出了请求。[INDEXEDDB] | — |
"ReadOnlyError " |
在“只读”事务中尝试执行变更操作。[INDEXEDDB] | — |
"VersionError " |
尝试以低于现有版本的方式打开数据库。[INDEXEDDB] | — |
"OperationError " |
操作因特定原因失败。 | — |
"NotAllowedError " |
当前上下文中用户代理或平台不允许请求,可能是因为用户拒绝了权限。 | — |
"OptOutError " |
用户选择退出了该过程。 | — |
2.8.2. DOMException
派生接口
当异常需要携带可供程序检测的额外信息,而这些信息超出了 DOMException
的名称范围时,规范作者可以创建一个接口,该接口继承自 DOMException
。这些接口必须遵循特定的规则,以确保开发者可以预测其行为。具体规则如下:
-
接口的标识符必须以
Error
结尾,并且不得与DOMException
名称表中的名称重复。 -
构造函数的第一个参数必须是可选的
DOMString
,命名为message,默认为空字符串,并且必须将实例的消息设置为message。 -
构造函数的第二个参数应为包含额外信息的字典。
这些要求意味着这些接口的继承 代码
属性将始终返回 0。
继承自 DOMException
的派生接口,携带了额外的“协议错误代码”,该错误代码来自于服务器通过某个假设的网络协议“协议 X”发送的数据,定义如下:
[Exposed =Window ,Serializable ]interface ProtocolXError :DOMException {constructor (optional DOMString message = "",ProtocolXErrorOptions options );readonly attribute unsigned long long errorCode ; };dictionary ProtocolXErrorOptions {required [EnforceRange ]unsigned long long errorCode ; };
每个 ProtocolXError
实例都有一个错误代码,是一个数字。
构造函数 new ProtocolXError(message, options)
的步骤如下:
ProtocolXError
对象是 可序列化对象。
它们的序列化步骤如下,给定 value 和 serialized:
- 根据
DOMException
序列化步骤,传递 value 和 serialized。 - 将 serialized 的 [[ErrorCode]] 设置为 value 的 错误代码。
它们的反序列化步骤如下,给定 serialized 和 value:
- 根据
DOMException
反序列化步骤,传递 serialized 和 value。 - 将 value 的 错误代码 设置为 serialized 的 [[ErrorCode]]。
要创建或抛出一个 DOMException
派生接口,提供其 接口 标识符以及构造它所需的额外信息。
2.9. 枚举
枚举是一种用于声明类型的定义(匹配DOMString
值,该值可以分配给属性或传递给操作。
enum identifier {"enum" ,"values" /* , ... */ };
枚举值通过以逗号分隔的
强烈建议枚举值全为小写,并且多个单词使用连字符分隔或不分隔,除非有特定原因使用其他命名方案。例如,指示应创建对象的枚举值可以命名为
"createobject
" 或 "create-object
"。在决定是否连字符分隔或不分隔枚举值单词时,请考虑相关 API 的一致性。
当字符串值不是有效的枚举值并赋值给属性或传递给枚举类型的操作参数时,行为是语言绑定特定的。
注意:在 JavaScript 绑定中,将无效的字符串值赋给属性时会被忽略,而在其他上下文(例如作为操作参数)中传递此类值时会抛出异常。
此规范中定义的没有适用于枚举的扩展属性。
Enum ::enum identifier { EnumValueList } ;
EnumValueList ::string EnumValueListComma
EnumValueListComma ::, EnumValueListString ε
EnumValueListString ::string EnumValueListComma ε
以下 IDL 片段定义了一个枚举,该枚举用作属性和操作参数的类型:
enum MealType {"rice" ,"noodles" ,"other" }; [Exposed =Window ]interface Meal {attribute MealType type ;attribute double size ; // 以克为单位undefined initialize (MealType type ,double size ); };
JavaScript 实现会限制可以分配给 type 属性或传递给 initializeMeal 函数的字符串,这些字符串必须是 枚举 中定义的字符串。
var meal= getMeal(); // 获取一个 Meal 实例。 meal. initialize( "rice" , 200 ); // 正常调用操作。 try { meal. initialize( "sandwich" , 100 ); // 抛出 TypeError。 } catch ( e) { } meal. type= "noodles" ; // 属性正常分配。 meal. type= "dumplings" ; // 属性分配被忽略。 meal. type== "noodles" ; // 计算结果为 true。
2.10. 回调函数
“Custom DOM Elements” 规范希望使用回调函数类型来提供平台对象函数。我们是否应该将“回调函数”重命名为仅“函数”,以明确它们可以用于两种目的?
回调函数
是一种定义(匹配
callback identifier =return_type (/* 参数... */);
注意:另请参见类似命名的 回调接口。
等号左边的 标识符 给出了 回调函数
的名称,等号右边的返回类型和参数列表(匹配
以下扩展属性适用于回调函数:
[LegacyTreatNonObjectAsNull
]。
CallbackOrInterfaceOrMixin ::callback CallbackRestOrInterface interface InterfaceOrMixin
CallbackRest ::identifier = Type ( ArgumentList ) ;
以下 IDL 片段 定义了一个用于 API 的 回调函数,该 API 会在操作完成时调用用户定义的函数。
callback AsyncOperationCallback =undefined (DOMString status ); [Exposed =Window ]interface AsyncOperations {undefined performOperation (AsyncOperationCallback whenFinished ); };
在 JavaScript 语言绑定中,函数对象 作为操作参数传递。
var ops= getAsyncOperations(); // 获取 AsyncOperations 的实例。 ops. performOperation( function ( status) { window. alert( "操作完成,状态为 " + status+ "." ); });
2.11. 类型定义
类型定义 是一种定义
(匹配
typedef type identifier ;
被赋予新名称的类型 在
Typedef ::typedef TypeWithExtendedAttributes identifier ;
以下 IDL 片段 展示了使用 类型定义 来允许使用简短的 标识符 代替较长的 序列类型。
[Exposed =Window ]interface Point {attribute double x ;attribute double y ; };typedef sequence <Point >Points ; [Exposed =Window ]interface Widget {boolean pointWithinBounds (Point p );boolean allPointsWithinBounds (Points ps ); };
2.12. 实现接口的对象
在一组 IDL 片段 的给定实现中, 一个对象可以被描述为 平台对象。
平台对象 是实现了 接口 的对象。
遗留平台对象
是 平台对象,它实现了没有
[Global
] 扩展属性
的接口,并且支持 索引属性、命名属性,或者两者兼有。
例如,在浏览器中,
浏览器实现的 DOM 对象(实现了如 Node
和 Document
这样的接口)为页面中运行的
JavaScript 提供对网页内容的访问权限,这些对象将被视为 平台对象。这些对象可能是异质对象,使用 C++ 语言实现,或者它们可能是原生的 JavaScript 对象。不管怎样,
一个给定的 IDL 片段集合的实现需要能够识别所有由该实现创建的 平台对象。这可以通过某种内部状态记录一个给定对象是否确实是该实现的一个平台对象,或者可能通过观察
该对象是由某个给定的内部 C++ 类实现的。具体来说,平台对象如何由一组 IDL 片段的给定实现识别是实现相关的。
系统中的所有其他对象不会被视为平台对象。例如,假设
一个在浏览器中打开的网页加载了一个 JavaScript 库,该库实现了 DOM Core。这个库
将被视为与浏览器提供的实现不同的实现。
由该 JavaScript 库创建的实现 Node
接口的对象
不会被浏览器实现视为实现 Node
的平台对象。
另一方面,回调接口
可以由任何 JavaScript 对象实现。这
允许 Web API 调用作者定义的操作。例如,DOM 事件的实现
允许作者通过提供实现了 EventListener
接口的对象来注册回调。
2.13. 类型
本节列出了 Web IDL 支持的类型、 每个类型对应的值集合或 Infra 类型, 以及该类型的常量的表示方式。
以下类型被称为整数类型:byte
、octet
、short
、unsigned short
、
long
、unsigned long
、
long long
和 unsigned long long
。
以下类型被称为数值类型:
整数类型、float
、unrestricted float
、
double
和
unrestricted double
。
原始类型
包括 bigint
、
boolean
,
以及数值类型。
字符串类型
包括 DOMString
、
所有枚举类型、
ByteString
和 USVString
。
缓冲区类型
包括 ArrayBuffer
和 SharedArrayBuffer
。
类型化数组类型 包括
Int8Array
、
Int16Array
、
Int32Array
、
Uint8Array
、
Uint16Array
、
Uint32Array
、
Uint8ClampedArray
、
BigInt64Array
、
BigUint64Array
、
Float16Array
、
Float32Array
、
和 Float64Array
。
object
类型、
所有 接口类型 和
所有 回调接口类型
被称为对象类型。
当从语言绑定的特定类型到 IDL 类型进行转换以调用操作或为属性分配值时, 在执行操作或属性分配的指定功能之前,将执行所有必要的转换。如果无法执行转换,则操作不会运行或 属性不会更新。在某些语言绑定中, 类型转换可能会导致抛出异常。 在这种情况下,这些异常将传播到尝试调用操作或 为属性赋值的代码中。
Type ::SingleType UnionType Null
TypeWithExtendedAttributes ::ExtendedAttributeList Type
SingleType ::DistinguishableType any PromiseType
UnionType ::( UnionMemberType or UnionMemberType UnionMemberTypes )
UnionMemberType ::ExtendedAttributeList DistinguishableType UnionType Null
UnionMemberTypes ::or UnionMemberType UnionMemberTypes ε
DistinguishableType ::PrimitiveType Null StringType Null identifier Null sequence < TypeWithExtendedAttributes > Null async_iterable < TypeWithExtendedAttributes > Null object Null symbol Null BufferRelatedType Null FrozenArray < TypeWithExtendedAttributes > Null ObservableArray < TypeWithExtendedAttributes > Null RecordType Null undefined Null
PrimitiveType ::UnsignedIntegerType UnrestrictedFloatType boolean byte octet bigint
UnrestrictedFloatType ::unrestricted FloatType FloatType
FloatType ::float double
UnsignedIntegerType ::unsigned IntegerType IntegerType
IntegerType ::short long OptionalLong
OptionalLong ::long ε
StringType ::ByteString DOMString USVString
PromiseType ::Promise < Type >
RecordType ::record < StringType , TypeWithExtendedAttributes >
Null ::? ε
2.13.1. 任意类型
any
类型类似于区分联合类型,因为它的每个值都有一个特定的非any
类型与之关联。例如,any
类型的一个值是
unsigned long
150,而另一个是 long
150。这些是不同的值。
any
值的特定类型称为其特定类型。(联合类型的值也有特定类型。)
2.13.2. undefined 类型
undefined
类型有一个唯一的值。
undefined
常量值在 IDL 中用
undefined
不能在任何情况下作为参数类型(在 操作、回调函数、构造函数操作等中),也不能作为 字典成员的类型,无论是直接使用还是在联合类型中使用。相反,应该使用可选参数或非必需的 字典成员。
注意: 此值以前拼写为 void
,并且在使用上受到更多限制。
2.13.3. 布尔类型
IDL 中的 boolean
常量值用
2.13.4. 字节类型
2.13.5. 八位字节类型
2.13.6. 短整型
2.13.7. 无符号短整型
unsigned short
类型对应于16 位无符号整数。
IDL 中的 unsigned short
常量值用
2.13.8. 长整型
2.13.9. 无符号长整型
unsigned long
类型对应于32 位无符号整数。
IDL 中的 unsigned long
常量值用
2.13.10. 长长整型
IDL 中的 long long
常量值用
2.13.11. 无符号长长整型
unsigned long long
类型对应于64 位无符号整数。
IDL 中的 unsigned long long
常量值用
2.13.12. 单精度浮点型
float
类型是一种浮点数值类型,对应于有限单精度 32 位 IEEE 754 浮点数的集合。[IEEE-754]
除非有特定原因需要使用 32 位浮点类型,否则规范应使用 double
而不是
float
,因为
double
可以表示的值集更接近 JavaScript Number。
2.13.13. 无限制单精度浮点型
unrestricted float
类型是一种浮点数值类型,对应于所有可能的单精度 32 位 IEEE 754 浮点数的集合,包括有限值、非有限值和特殊的“非数字”值 (NaN)。[IEEE-754]
IDL 中的 unrestricted float
常量值用
2.13.14. 双精度浮点型
double
类型是一种浮点数值类型,对应于有限双精度 64 位 IEEE 754 浮点数的集合。[IEEE-754]
2.13.15. 无限制双精度浮点型
unrestricted double
类型是一种浮点数值类型,对应于所有可能的双精度 64 位 IEEE 754 浮点数的集合,包括有限值、非有限值和特殊的“非数字”值 (NaN)。[IEEE-754]
IDL 中的 unrestricted double
常量值用
2.13.16. 大整数类型
bigint
类型是一种任意整数类型,范围不受限制。
2.13.17. DOM字符串类型
注意: DOMString
类型的值。要允许 DOMString
,在
IDL 中写作 DOMString?
。
注意: DOMString
值可能包含未配对的代理码点。如果不希望如此,请使用 USVString
。
IDL 中没有办法表示常量 DOMString
值,尽管 DOMString
字典成员默认值和操作可选参数默认值可以设置为字符串字面量的值。
2.13.18. 字节字符串类型
ByteString
类型对应于字节序列。
在 IDL 中没有办法表示 ByteString
的常量值,但可以将 ByteString
的字典成员 默认值 和 操作的可选参数 默认值
设置为 字符串字面量的值。
规范应仅在与同时使用字节和字符串的协议(如 HTTP)进行交互时使用 ByteString
。一般来说,字符串应使用
DOMString
值表示,即使预期字符串的值总是 ASCII 或某些 8 位字符编码。应使用带有 octet
或
byte
元素的序列或冻结数组,或者使用
Uint8Array
或 Int8Array
来保存 8 位数据,而不是使用 ByteString
。
2.13.19. USV字符串类型
USVString
类型对应于标量值字符串。
根据上下文,
它们可以被视为代码单元或标量值的序列。
在 IDL 中没有办法表示 USVString
的常量值,但可以将 USVString
的字典成员 默认值 和 操作可选参数 默认值
设置为 字符串字面量的值。
规范应仅在执行文本处理并需要一串标量值的 API 中使用 USVString
。大多数使用字符串的
API 应使用 DOMString
,它不对字符串中的代码单元进行任何解释。如果不确定,请使用 DOMString
。
2.13.20. 对象类型
object
类型对应于所有可能的非空对象引用集合。
在 IDL 中没有办法表示 object
常量值。
若要表示包含所有可能对象引用和 object?
。
2.13.21. symbol
symbol
类型对应于所有可能的符号值集合。符号值是不可见的非对象
值,但具有标识(即,仅等于其自身)。
在 IDL 中没有办法表示 symbol
的常量值。
2.13.22. 接口类型
用于标识接口的标识符,用来指代与所有可能的非空对象引用集合对应的类型,这些对象实现了该接口。
接口类型的 IDL 值仅由对象引用表示。
在 IDL 中没有办法表示特定接口类型的常量对象引用值。
若要表示包含所有可能引用该接口实现的对象及
2.13.23. 回调接口类型
用于标识回调接口的标识符,用来指代与所有可能的非空对象引用集合对应的类型。
回调接口类型的 IDL 值由对象引用和回调上下文元组表示。回调上下文是语言绑定的特定值,用于存储在语言绑定的特定对象引用被转换为 IDL 值时的执行上下文信息。
注意: 对于 JavaScript 对象,回调上下文用于保存将对象值转换为 IDL 回调接口类型值时的当前设置对象的引用。参见§ 3.2.16 回调接口类型。
在 IDL 中没有办法表示特定回调接口类型的常量对象引用值。
若要表示包含所有可能对象引用及
2.13.24. 字典类型
用于标识字典的标识符,用来指代与符合该字典定义的所有字典集合对应的类型。
当从上下文中隐含理解为将有序映射视为特定字典类型的实例时,有序映射的字面语法也可以用于表示字典。然而,IDL 片段中没有办法表示常量字典值。
2.13.25. 枚举类型
用于标识枚举的标识符,用来指代一个类型,该类型的值为字符串(代码单元序列,如DOMString
)。这些字符串是枚举的值。
与 DOMString
相似,IDL 中没有办法表示常量枚举值,但枚举类型的 字典成员 默认值 和
操作的可选参数
默认值可以设置为 字符串字面量的值。
2.13.26. 回调函数类型
标识回调函数的标识符,用来指代类型,其值是对具有指定签名的函数对象的引用。
注意: 如果在 定义中的 扩展属性指定了 [LegacyTreatNonObjectAsNull
],则其值可以是对非函数对象的引用。
回调函数类型的 IDL 值由对象引用和回调上下文元组表示。
注意: 与回调接口类型类似,回调上下文用于保存将 JavaScript 对象值转换为 IDL 回调函数类型值时的当前设置对象的引用。参见§ 3.2.19 回调函数类型。
在 IDL 中没有办法表示常量回调函数值。
2.13.27. 可空类型 — T?
可空类型是从现有类型(称为内部类型)构建的 IDL 类型,该类型允许其值集合中包含额外的
-
any
, -
另一个可空类型,或
注意: 虽然字典类型通常是可空的,但作为操作参数或字典成员时,它们不能为可空类型。
可空类型的常量值在 IDL 中的表示方式与其内部类型的常量值表示方式相同,或使用
例如,允许 boolean?
:
[Exposed =Window ]interface NetworkFetcher {undefined get (optional boolean ?areWeThereYet =false ); };
以下接口有两个属性:其中一个的值可以是 DOMString
或 Node
对象引用或
[Exposed =Window ]interface Node {readonly attribute DOMString ?namespaceURI ;readonly attribute Node ?parentNode ; // ... };
2.13.28. 序列类型 — sequence<T>
sequence<T> 类型是一种参数化类型,其值为类型 T 的(可能为零长度的)列表。
序列始终按值传递。在序列用某种对象表示的语言绑定中,将序列传递给 平台对象不会导致该对象保留对序列的引用。同样,从平台对象返回的任何序列都将是副本,所做的修改将对平台对象不可见。
当从上下文中隐含知道列表被视为序列时,可以使用列表的字面语法来表示序列。然而,在 IDL 片段中没有办法表示常量序列值。
注意: 此限制的存在是为了让规范编写者和 API 用户清楚序列是被复制的,而不是引用被传递。建议通过使用一对操作来获取和设置序列,而不是使用可写的序列类型属性。
任何列表都可以被隐式地视为
sequence<T>
,只要它只包含类型 T 的项。
2.13.29. 异步可迭代类型 — async iterable<T>
一个异步可迭代类型是一个参数化类型,其值是对可以产生类型为 T 的值的异步可迭代、可能无限的序列的对象的引用。
与序列(所有值都预先已知的固定长度列表)不同,由异步可迭代对象创建的异步可迭代序列是惰性的。它们的值可能仅在迭代期间异步产生,因此在创建异步可迭代对象时可能不知道值或长度。
在语言绑定中,异步可迭代对象通过引用传递,其中它们由对象表示。这意味着将异步可迭代对象传递给平台对象将导致该对象保留对异步可迭代对象的引用。类似地,从平台对象返回的任何异步可迭代对象都将是对同一对象的引用,并且对其进行的修改将对平台对象可见。这与始终按值传递的序列相反。
注意:异步可迭代对象不能从 IDL 构造。如果从操作返回,或用作字典成员的类型,则异步可迭代对象将源自宿主环境,并通过语言绑定转换为 IDL 类型。操作可能希望返回一个具有异步可迭代声明的接口,而不是从 IDL 操作返回异步可迭代对象。
IDL 中没有办法表示异步可迭代值。
2.13.30. 记录类型 — record<K, V>
记录类型 是一种参数化类型,其值为具有
K 实例的有序映射,其键为
K 的实例,值为 V 的实例。K 必须是 DOMString
、USVString
或 ByteString
之一。
当从上下文中隐含知道映射被视为记录时,可以使用有序映射的字面语法来表示记录。然而,在 IDL 片段中没有办法表示常量记录值。
记录总是按值传递。在记录由某种对象表示的语言绑定中,将记录传递给平台对象不会导致该对象保留对记录的引用。类似地,从平台对象返回的任何记录都将是副本,对其进行的修改对平台对象不可见。
任何有序映射都可以隐式地视为
record<K, V>
,只要它仅包含其键均为
K 类型且其值均为 V 类型的条目。
2.13.31. Promise 类型 — Promise<T>
promise 类型是一种参数化类型,其值是对对象的引用,这些对象“用作推迟(可能是异步)计算结果的占位符”。有关 promise 对象语义的详细信息,请参阅 JavaScript 规范的第 25.4 节。
Promise 类型不可为空,但 T 可以是可空类型。
在 IDL 中没有办法表示 promise 值。
2.13.32. 联合类型
联合类型是一种类型,其值的集合是两个或多个其他类型的联合。联合类型(匹配
例如,你可以写 (Node 或 DOMString)
或 (double 或 sequence<double>)
。当对联合类型应用
(Node 或 DOMString)?
。
注意,联合类型的成员类型不会深入嵌套的联合类型。因此,对于
(double or (sequence<long> or Event) or (Node or DOMString)?)
,成员类型是
double
、(sequence<long> or Event)
和
(Node or DOMString)?
。
与 any
类型类似,联合类型的值具有特定类型,即与该值匹配的特定成员类型。
注意: 例如,联合类型
(Node or (sequence<long> or Event) or (XMLHttpRequest or DOMString)? or sequence<(sequence<double> or NodeList)>)
的扁平化成员类型为
Node
、sequence<long>
、Event
、XMLHttpRequest
、DOMString
和 sequence<(sequence<double> or NodeList)>
。
可空成员类型的数量 必须为 0 或 1。如果为 1,联合类型中也不能包含 字典类型。
一个类型包含可空类型,如果:
可以创建bigint和数值类型的联合类型。但是,这通常仅应用于如NumberFormat等格式化数值的接口,而不是用于计算。如果创建了这样的联合类型,并将数值类型转换为bigint,则可能会引入精度错误。如果需要使用此功能,请提交问题。
一个类型包含undefined,如果:
-
该类型是
undefined
,或者 -
该类型是可空类型,并且其内在类型包含undefined,或者
-
该类型是带注释类型,并且其内在类型包含undefined,或者
-
该类型是联合类型,并且其中一个成员类型包含undefined。
联合类型的常量值在IDL中表示方式与其成员类型的常量值表示方式相同。
DistinguishableType ::PrimitiveType Null StringType Null identifier Null sequence < TypeWithExtendedAttributes > Null async iterable < TypeWithExtendedAttributes > Null object Null symbol Null BufferRelatedType Null FrozenArray < TypeWithExtendedAttributes > Null ObservableArray < TypeWithExtendedAttributes > Null RecordType Null undefined Null
2.13.33. 带注释的类型
可以通过在现有类型上指定某些扩展属性,从现有类型创建额外类型。此类类型称为带注释的类型,它们注释的类型称为内在类型。
以下扩展属性适用于类型:[AllowResizable
],[AllowShared
],[Clamp
],[EnforceRange
],以及[LegacyNullToEmptyString
]。
与IDL类型type相关联的扩展属性按以下步骤确定:
-
令extended attributes为一个新的空集合。
-
如果type出现在
TypeWithExtendedAttributes 的产生式中,追加该产生式中的ExtendedAttributeList 中的每个扩展属性到extended attributes。 -
如果type直接出现在
Type 产生式中的Argument 产生式中,追加所有适用于类型的扩展属性到extended attributes。 -
如果type直接出现在
Type 产生式中的DictionaryMember 产生式中,追加所有适用于类型的扩展属性到extended attributes。 -
返回extended attributes。
对于任何类型,其关联的扩展属性只能包含适用于类型的扩展属性。
2.13.34. 缓冲源类型
有多种类型对应于表示数据缓冲区或缓冲区视图的所有可能的非空引用对象的集合。下表列出了这些类型及其表示的缓冲区或视图类型。
类型 | 缓冲区类型 |
---|---|
ArrayBuffer |
一个对象,持有指向固定字节数缓冲区的指针(该指针可以为空) |
SharedArrayBuffer |
一个对象,持有指向共享缓冲区的指针(该指针不能为空),缓冲区的字节数是固定的 |
DataView |
指向缓冲区类型实例的视图,允许按类型访问存储在缓冲区任意偏移量处的整数和浮点数值 |
Int8Array |
指向缓冲区类型实例的视图,将其作为指定位数的二进制补码有符号整数数组进行暴露 |
Int16Array |
|
Int32Array |
|
BigInt64Array |
|
Uint8Array |
指向缓冲区类型实例的视图,将其作为指定位数的无符号整数数组进行暴露 |
Uint16Array |
|
Uint32Array |
|
BigUint64Array |
|
Uint8ClampedArray |
一个缓冲区类型实例的视图,该视图将其公开为具有钳位转换的8 位无符号整数数组 |
Float16Array |
指向缓冲区类型实例的视图,将其作为指定位数的IEEE 754浮点数数组进行暴露;Float16Array对应于ECMAScript提案[PROPOSAL-FLOAT16ARRAY]。 |
Float32Array |
|
Float64Array |
注意:这些类型均对应于JavaScript中定义的类。
在IDL中无法表示这些类型的常量值。
在规范文本层面,IDL缓冲源类型只是对对象的引用。要检查或操作缓冲区中的字节,规范文本需要使用§ 3.2.26 缓冲源类型中的算法。
BufferRelatedType ::ArrayBuffer SharedArrayBuffer DataView Int8Array Int16Array Int32Array Uint8Array Uint16Array Uint32Array Uint8ClampedArray BigInt64Array BigUint64Array Float16Array Float32Array Float64Array
2.13.35. 冻结数组类型 — FrozenArray<T>
冻结数组类型 是一种参数化的类型,其值是对持有不可修改值的固定长度数组对象的引用。数组中的值类型为 T。
冻结数组类型仅可用于定义在 接口 上的 常规属性 或 静态属性。
[Exposed =Window ]interface PersonalPreferences {readonly attribute FrozenArray <DOMString >favoriteColors ;attribute FrozenArray <DOMString >favoriteFoods ;undefined randomizeFavoriteColors (); };
这些属性的行为可以定义如下:
每个PersonalPreferences
具有关联的喜爱的颜色,一个FrozenArray
<DOMString
>,最初等于从 « "purple
", "aquamarine
" » 中创建一个冻结数组 的结果。每个
PersonalPreferences
具有关联的喜爱的食物,一个FrozenArray
<DOMString
>,最初等于从空列表中创建一个冻结数组的结果。
favoriteColors
的 getter 步骤是返回 this 的喜爱的颜色。
favoriteFoods
的 getter 步骤是返回 this 的喜爱的食物。
favoriteFoods
的 setter 步骤是将 this 的喜爱的食物设置为 给定的值。
randomizeFavoriteColors()
的 方法步骤如下:
由于 FrozenArray<T> 值是引用,因此它们不同于序列类型,后者是按值传递的值列表。
在 IDL 中没有表示常量冻结数组值的方法。
2.13.36. 可观察数组类型 — ObservableArray<T>
可观察数组类型 是一种参数化的类型,其值是对类型为 T 的可变对象列表的引用,以及在开发者代码修改该列表内容时执行的行为。
参数化类型 T 不得是 字典类型、序列类型、记录类型或 可观察数组类型,但 T 可以为可空类型。
类似于 序列类型 和 冻结数组类型,可观察数组类型围绕 JavaScript 数组类型,强加额外的语义。
可观察数组类型仅可用作定义在 接口 上的 常规属性 的类型。
对于类型为可观察数组的属性,规范作者可以指定一系列算法:
-
设置索引值,接受即将在可观察数组中设置的 IDL 值以及设置的索引;
-
删除索引值,接受即将从可观察数组中删除的 IDL 值以及要删除的索引。
这两个算法都是可选的,如果没有提供,默认行为将是无操作。任何一个算法都可能抛出异常,例如拒绝无效值。
请注意,当 JavaScript 代码将现有索引设置为新值时,这首先会调用 删除索引值 算法以删除现有值,然后调用 设置索引值 算法来设置新值。
每个类型为 可观察数组类型 的 常规属性 都有一个 备份列表,它是一个 列表,初始为空。规范作者可以修改备份列表的内容,这将自动反映在 JavaScript 代码观察到的可观察数组的内容中。同样,JavaScript 代码对可观察数组内容的任何修改将在通过 设置索引值 和 删除索引值 算法后反映回备份列表中。
在 IDL 中无法表示常量的可观察数组值。
[Exposed =Window ]interface Building {attribute ObservableArray <Employee >employees ; };
该属性的行为可以定义如下:
Building
的employees
属性的 设置索引值算法,给定 employee 和 index:
如果 employee 今天不允许进入大楼,则抛出 "
NotAllowedError
"DOMException
。如果 index 大于 200,则抛出 "
QuotaExceededError
"DOMException
。让 employee 开始工作!
Building
的employees
属性的 删除索引值算法,给定 employee 和 index:
通知安保 employee 已经离开大楼。
然后,JavaScript 代码可以通过多种方式操作 employees
属性:
// 获取一个 Building 的实例。 const building= getBuilding(); building. employees. push( new Employee( "A" )); building. employees. push( new Employee( "B" )); building. employees. push( new Employee( "C" )); building. employees. splice( 2 , 1 ); const employeeB= building. employees. pop(); building. employees= [ new Employee( "D" ), employeeB, new Employee( "C" )]; building. employees. length= 0 ; // 将会抛出异常: building. employees. push( "不是 Employee;而是字符串" );
所有这些操作都会经过上面定义的 设置索引值 算法,在满足所描述的条件时可能抛出异常。 它们还会执行相应的副作用,如在 删除索引值 算法中列出的副作用。
需要注意的是,上述代码示例中的所有 JavaScript 数组方法都可以在可观察数组上使用。它完全像一个 Array
实例一样行为:
const normalArray= []; // 如果 building.employees 被定义为索引属性 getter 接口:normalArray // 将包含单个项目,即 building.employees。 // // 对于可观察数组(和冻结数组):normalArray 包含 building.employees 内的所有项目。 normalArray. concat( building. employees); // names 是一个 JavaScript 数组。 const names= building. employees. map( employee=> employee. name); // 通过了各种品牌检查: console. assert( building. employeesinstanceof Array); console. assert( Array. isArray( building. employees)); console. assert( building. employees. constructor === Array); // 即使在 JSON.stringify 中,也被当作数组处理!(注意外部的 []。) console. assert( JSON. stringify( building. employees) === `[{}]` );
2.14. 扩展属性
一个 扩展属性
是一种注解,
可以出现在 定义、
注解类型、
接口成员、
接口混入成员、
回调接口成员、
命名空间成员、
字典成员 和
操作 参数中, 用于控制语言绑定如何处理这些结构。
扩展属性用
语法符号 | 形式 | 示例 |
---|---|---|
|
不带参数 | [Replaceable]
|
|
带参数列表 | 目前未使用;以前使用 [Constructor(double x, double y)]
|
|
带命名参数列表 | [LegacyFactoryFunction=Image(DOMString src)]
|
|
带标识符 | [PutForwards=name]
|
|
带标识符列表 | [Exposed=(Window,Worker)]
|
|
带通配符 | [Exposed=*]
|
本规范定义了适用于 JavaScript 语言绑定的多个扩展属性,它们在 § 3.3 扩展属性 中进行了描述。 每个扩展属性定义将说明允许的上述五种形式中的哪一种(或多种)。
ExtendedAttributeList ::[ ExtendedAttribute ExtendedAttributes ] ε
ExtendedAttributes ::, ExtendedAttribute ExtendedAttributes ε
ExtendedAttribute ::( ExtendedAttributeInner ) ExtendedAttributeRest [ ExtendedAttributeInner ] ExtendedAttributeRest { ExtendedAttributeInner } ExtendedAttributeRest Other ExtendedAttributeRest
ExtendedAttributeRest ::ExtendedAttribute ε
ExtendedAttributeInner ::( ExtendedAttributeInner ) ExtendedAttributeInner [ ExtendedAttributeInner ] ExtendedAttributeInner { ExtendedAttributeInner } ExtendedAttributeInner OtherOrComma ExtendedAttributeInner ε
Other ::integer decimal identifier string other - -Infinity . ... : ; < = > ? * ByteString DOMString FrozenArray Infinity NaN ObservableArray Promise USVString any bigint boolean byte double false float long null object octet or optional record sequence short symbol true unsigned undefined ArgumentNameKeyword BufferRelatedType
OtherOrComma ::Other ,
IdentifierList ::identifier Identifiers
Identifiers ::, identifier Identifiers ε
ExtendedAttributeNoArgs ::identifier
ExtendedAttributeArgList ::identifier ( ArgumentList )
ExtendedAttributeIdent ::identifier = identifier
ExtendedAttributeWildcard ::identifier = *
ExtendedAttributeIdentList ::identifier = ( IdentifierList )
ExtendedAttributeNamedArgList ::identifier = identifier ( ArgumentList )
3. JavaScript 绑定
本节描述了使用 § 2 接口定义语言 编写的定义如何对应于 ECMAScript 语言规范 中的 JavaScript 构造,详见 [ECMA-262]。
除非另有规定,本节中定义的对象是普通对象,详见 ECMAScript § 10.1 Ordinary Object Internal Methods and Internal Slots,如果对象是 函数对象,详见 ECMAScript § 10.3 Built-in Function Objects。
本节可以重新定义某些对象的内部方法和内部槽。其他规范也可以重写 平台对象 (即 接口 的实例) 的内部方法或内部槽的定义。 这些具有更改语义的对象应按照异质对象的规则处理。
由于覆盖 JavaScript 内部对象方法是一种低级操作,可能会导致对象的行为与普通对象不同,
除非出于安全或兼容性考虑,否则不应使用此功能。
当前用于定义 HTMLAllCollection
和 Location
接口。
[HTML]
除非另有规定,本节和其他规范中定义的奇异对象与普通对象具有相同的内部插槽,并且所有未给出替代定义的内部方法均与普通对象的那些相同。
除非另有规定,本节中定义的对象的 [[Extensible]] 内部槽的值为
除非另有规定,本节中定义的对象的 [[Prototype]] 内部槽是 %Object.prototype%
。
本节描述的一些对象定义了一个 类字符串,
这是在 Object.prototype.toString
返回的字符串中包含的字符串。
如果一个对象有一个类字符串
classString,那么该对象在创建时必须有一个属性,其名称为 %Symbol.toStringTag%
符号,其 PropertyDescriptor 为 {[[Writable]]:
本节中的算法使用 ECMAScript § 5.2 算法约定中描述的约定,例如步骤和子步骤的使用、数学运算的使用等等。本节还可能引用 ECMA-262 其他部分中定义的抽象操作和表示法。
当一个算法说要抛出一个
SomethingError
时,这意味着在当前领域中构造一个新的 JavaScript
SomethingError
对象并将其抛出,就像 ECMA-262 中的算法所做的那样。
注意,算法步骤可以调用其他算法和抽象操作,而不显式处理它们抛出的异常。当算法或抽象操作抛出异常且调用方未显式处理时, 该异常将导致算法结束并向其调用者传播,依此类推。
由于 ToString 可以抛出异常(例如,如果传递了对象
({ toString: function() { throw 1 } })
),
并且该异常在上述算法中未处理,那么如果抛出了异常,它将导致该算法结束并向其调用者传播,如果有的话。
3.1. JavaScript 环境
在给定的一组 IDL 片段 的 JavaScript 实现中,将存在若干对应于这些 IDL 片段 定义的 JavaScript 对象。 这些对象被称为 初始对象, 包括以下内容:
每个 领域 必须拥有一组唯一的 初始对象,这些对象会在与该领域关联的任何 JavaScript 执行上下文进入之前创建,但在该领域的 全局对象 创建之后。给定领域中所有初始对象的 [[Prototype]] 必须来自该领域。
在 HTML 用户代理中,当创建多个框架或窗口时可以存在多个 领域。 每个框架或窗口都会有自己的一组 初始对象,如下 HTML 文档所示:
<!DOCTYPE html> < title > 不同的领域</ title > < iframe id = a ></ iframe > < script > var iframe= document. getElementById( "a" ); var w= iframe. contentWindow; // 框架中的全局对象 Object== w. Object; // 评估结果为 false,按 ECMA-262 标准 Node== w. Node; // 评估结果为 false iframeinstanceof w. Node; // 评估结果为 false iframeinstanceof w. Object; // 评估结果为 false iframe. appendChildinstanceof Function; // 评估结果为 true iframe. appendChildinstanceof w. Function; // 评估结果为 false </ script >
注意:所有 接口 定义它们在 哪些 领域 中 暴露。 这允许,例如,Web Workers 的 领域 暴露与 Web 页面领域不同的一组支持的接口。
尽管在撰写本文时 JavaScript 规范尚未反映这一点,但每个 JavaScript 对象都必须具有一个 关联的 领域。 目前,尚未完全指定将对象与领域关联的机制。然而,我们注意到,对于 平台对象,关联的领域等于该对象的 相关领域, 而对于非异质 函数对象(即非 可调用 代理,且非绑定函数), 关联的领域等于函数对象的 [[Realm]] 内部槽的值。
3.2. JavaScript 类型映射
本节描述了 IDL 中的类型如何映射到 JavaScript 中的类型。
以下每个小节描述了给定 IDL 类型的值在 JavaScript 中的表示方式。对于每种 IDL 类型,都描述了 JavaScript 值在传递给期望该类型的平台对象时如何转换为 IDL 值,以及该类型的 IDL 值从平台对象返回时如何转换为 JavaScript 值。
请注意,以下小节和算法也适用于通过将扩展属性应用于其头部命名的类型而创建的带注解类型。
3.2.1. any
由于 IDL any
类型是所有其他
IDL 类型的联合,因此它可以对应于任何 JavaScript 值类型。
IDL any
值根据本节其余部分描述的转换
IDL any
值的特定类型的规则转换为 JavaScript 值。
3.2.2. undefined
通过返回唯一的 undefined
值(忽略 V),将 JavaScript 值 V 转换为
IDL undefined
值。
唯一的 IDL undefined
值转换为 JavaScript
3.2.3. boolean
IDL boolean
值
true
转换为 JavaScript boolean
值
false
转换为 JavaScript
3.2.4. 整数类型
本节中使用的数学运算,包括 ECMAScript § 5.2 算法约定中定义的那些,应理解为对数学实数计算精确的数学结果。
实际上,当 x 是一个数字值时,“对 x 进行运算”是“对表示与 x 相同数值的数学实数进行运算”的简写。
3.2.4.1. byte
通过运行以下算法,将 JavaScript 值 V 转换为 IDL byte
值:
-
令 x 为 ? ConvertToInt(V, 8, "
signed
")。 -
返回表示与 x 相同数值的 IDL
byte
值。
将 IDL byte
值转换为 JavaScript 值的结果是一个表示与 IDL byte
值相同数值的数字。该数字值将是范围 [−128, 127] 内的整数。
3.2.4.2. octet
通过运行以下算法,将 JavaScript 值 V 转换为 IDL octet
值:
-
令 x 为 ? ConvertToInt(V, 8, "
unsigned
")。 -
返回表示与 x 相同数值的 IDL
octet
值。
将 IDL octet
值转换为 JavaScript 值的结果是一个表示与 IDL octet
值相同数值的数字。该数字值将是范围 [0, 255] 内的整数。
3.2.4.3. short
通过运行以下算法,将 JavaScript 值 V 转换为 IDL short
值:
-
令 x 为 ? ConvertToInt(V, 16, "
signed
")。 -
返回表示与 x 相同数值的 IDL
short
值。
将 IDL short
值转换为 JavaScript 值的结果是一个表示与 IDL short
值相同数值的数字。该数字值将是范围 [−32768, 32767] 内的整数。
3.2.4.4. unsigned short
通过运行以下算法,将 JavaScript 值 V 转换为 IDL unsigned short
值:
-
令 x 为 ? ConvertToInt(V, 16, "
unsigned
")。 -
返回表示与 x 相同数值的 IDL
unsigned short
值。
将 IDL unsigned short
值转换为 JavaScript 值的结果是一个表示与 IDL unsigned short
值相同数值的数字。该数字值将是范围 [0, 65535] 内的整数。
3.2.4.5. long
通过运行以下算法,将 JavaScript 值 V 转换为 IDL long
值:
-
令 x 为 ? ConvertToInt(V, 32, "
signed
")。 -
返回表示与 x 相同数值的 IDL
long
值。
将 IDL long
值转换为 JavaScript 值的结果是一个表示与 IDL long
值相同数值的数字。该数字值将是范围 [−2147483648, 2147483647] 内的整数。
3.2.4.6. unsigned long
通过运行以下算法,将 JavaScript 值 V 转换为 IDL unsigned long
值:
-
令 x 为 ? ConvertToInt(V, 32, "
unsigned
")。 -
返回表示与 x 相同数值的 IDL
unsigned long
值。
将 IDL unsigned long
值转换为 JavaScript 值的结果是一个表示与 IDL unsigned long
值相同数值的数字。该数字值将是范围 [0, 4294967295] 内的整数。
3.2.4.7. long long
通过运行以下算法,将 JavaScript 值 V 转换为 IDL long long
值:
-
令 x 为 ? ConvertToInt(V, 64, "
signed
")。 -
返回表示与 x 相同数值的 IDL
long long
值。
将 IDL long long
值转换为 JavaScript 值的结果是一个数字值,它表示最接近 long long
的数值,如果存在两个同样接近的值,则选择具有偶数有效数的数值。如果 long long
在范围 [−253 + 1, 253 − 1] 内,则该数字将能够精确表示与 long long
相同的值。
3.2.4.8. unsigned long long
通过运行以下算法,将 JavaScript 值 V 转换为 IDL unsigned long long
值:
-
令 x 为 ? ConvertToInt(V, 64, "
unsigned
")。 -
返回表示与 x 相同数值的 IDL
unsigned long long
值。
将 IDL unsigned long long
值转换为 JavaScript 值的结果是一个数字值,它表示最接近 unsigned long long
的数值,如果存在两个同样接近的值,则选择具有偶数有效数的数值。如果 unsigned long long
小于或等于 253 − 1,则该数字将能够精确表示与 unsigned long long
相同的值。
3.2.4.9. 抽象操作
ConvertToInt(V, bitLength, signedness):
-
如果 bitLength 是 64,则:
-
否则,如果 signedness 是 "
unsigned
",则:-
令 lowerBound 为 0。
-
令 upperBound 为 2bitLength − 1。
-
-
否则:
-
令 lowerBound 为 -2bitLength − 1。
-
令 upperBound 为 2bitLength − 1 − 1。
-
-
如果 x 是 −0,则将 x 设置为 +0。
-
如果转换是到与 [
EnforceRange
] 扩展属性关联的 IDL 类型,则:-
将 x 设置为 IntegerPart(x)。
-
返回 x。
-
如果 x 是
NaN 、+0、+∞ 或 −∞,则返回 +0。 -
将 x 设置为 IntegerPart(x)。
-
将 x 设置为 x 模 2bitLength。
-
如果 signedness 是 "
signed
" 且 x ≥ 2bitLength − 1,则返回 x − 2bitLength。 -
否则,返回 x。
3.2.5. float
将 IDL float
值转换为 JavaScript 值的结果是表示与 IDL float
值相同数值的数字值。
3.2.6. unrestricted float
通过运行以下算法,将 JavaScript 值 V 转换为 IDL unrestricted float
值:
-
如果 x 是
NaN ,则返回表示具有位模式 0x7fc00000 [IEEE-754] 的 IEEE 754 NaN 值的 IDLunrestricted float
值。 -
令 S 为有限 IEEE 754 单精度浮点值的集合,但不包括 −0,但添加了两个特殊值:2128 和 −2128。
-
令 y 为 S 中最接近 x 的数字,如果存在两个同样接近的值,则选择具有偶数有效数的数字。(为此目的,两个特殊值 2128 和 −2128 被认为具有偶数有效数。)
-
如果 y 是 2128,则返回 +∞。
-
如果 y 是 −2128,则返回 −∞。
-
如果 y 是 +0 且 x 是负数,则返回 −0。
-
返回 y。
注意:由于只有一个 JavaScript
将 IDL unrestricted float
值转换为 JavaScript 值的结果是一个数字:
-
如果 IDL
unrestricted float
值是 NaN,则数字值为NaN 。 -
否则,数字值是表示与 IDL
unrestricted float
值相同数值的那个值。
3.2.7. double
将 IDL double
值转换为 JavaScript 值的结果是表示与 IDL double
值相同数值的数字值。
3.2.8. unrestricted double
通过运行以下算法,将 JavaScript 值 V 转换为 IDL unrestricted double
值:
-
如果 x 是
NaN ,则返回表示具有位模式 0x7ff8000000000000 [IEEE-754] 的 IEEE 754 NaN 值的 IDLunrestricted double
值。 -
返回表示与 x 相同数值的 IDL
unrestricted double
值。
注意:由于只有一个 JavaScript
将 IDL unrestricted double
值转换为 JavaScript 值的结果是一个数字:
-
如果 IDL
unrestricted double
值是 NaN,则数字值为NaN 。 -
否则,数字值是表示与 IDL
unrestricted double
值相同数值的那个值。
3.2.9. bigint
3.2.10. DOMString
将 IDL DOMString
值转换为 JavaScript 值的结果是表示与 IDL DOMString
所表示的相同代码单元序列的字符串值。
3.2.11. ByteString
通过运行以下算法,将 JavaScript 值 V 转换为 IDL ByteString
值:
将 IDL ByteString
值转换为 JavaScript 值的结果是一个字符串值,其长度是 ByteString
的长度,并且其每个元素的值是 ByteString
相应元素的值。
3.2.12. USVString
3.2.13. object
IDL object
值由 JavaScript 对象值表示。
将 IDL object
值转换为 JavaScript 值的结果是表示对 IDL object
所表示的相同对象的引用的对象值。
3.2.14. symbol
IDL symbol
值由 JavaScript Symbol 值表示。
将 IDL symbol
值转换为 JavaScript 值的结果是表示对 IDL symbol
所表示的相同符号的引用的 Symbol 值。
3.2.15. 接口类型
IDL 接口类型值由 JavaScript 对象值(包括函数对象)表示。
将 IDL 接口类型值转换为 JavaScript 值的结果是表示对 IDL 接口类型值所表示的相同对象的引用的对象值。
3.2.16. 回调接口类型
IDL 回调接口类型值由 JavaScript 对象值(包括函数对象)表示。
将 IDL 回调接口类型值转换为 JavaScript 值的结果是表示对 IDL 回调接口类型值所表示的相同对象的引用的对象值。
3.2.17. 字典类型
IDL 字典类型值由 JavaScript 对象值表示。对象(或其原型链)上的属性对应于字典成员。
通过运行以下算法(其中 D 是字典类型),将 JavaScript 值 jsDict 转换为 IDL 字典类型值:
-
如果 jsDict 不是对象并且 jsDict 既不是
undefined 也不是null ,则抛出TypeError
。 -
令 idlDict 为一个空的有序映射,表示类型为 D 的字典。
-
令 dictionaries 为一个列表,其中包含 D 以及 D 的所有继承字典,按从最少派生到最多派生的顺序排列。
-
对于 dictionaries 中的每个字典 dictionary,按顺序:
-
对于在 dictionary 上声明的每个字典成员 member,按字典顺序:
-
-
返回 idlDict。
注意:在 JavaScript 对象上查找字典成员的顺序不一定与对象的属性枚举顺序相同。
通过运行以下算法(其中 D 是字典),将 IDL 字典值 V 转换为 JavaScript 对象值:
-
令 dictionaries 为一个列表,其中包含 D 以及 D 的所有继承字典,按从最少派生到最多派生的顺序排列。
-
对于 dictionaries 中的每个字典 dictionary,按顺序:
-
返回 O。
3.2.18. 枚举类型
IDL 枚举类型由 JavaScript 字符串值表示。
将 IDL 枚举类型值转换为 JavaScript 值的结果是表示与枚举值相同的代码单元序列的字符串值。
3.2.19. 回调函数类型
IDL 回调函数类型由
JavaScript 函数对象表示,但在 [LegacyTreatNonObjectAsNull
]
情况下除外,此时它们可以是任何对象。
通过运行以下算法,将 JavaScript 值 V 转换为 IDL 回调函数类型值:
-
如果调用 IsCallable(V) 的结果是
false 并且不是因为 V 被分配给类型为可为空的回调函数(该回调函数使用 [LegacyTreatNonObjectAsNull
] 进行注释)的属性而执行到 IDL 值的转换,则抛出TypeError
。
将 IDL 回调函数类型值转换为 JavaScript 值的结果是对 IDL 回调函数类型值所表示的相同对象的引用。
3.2.20. 可为空类型 — T?
IDL 可为空类型值由对应于内部 IDL 类型的 JavaScript
类型的值或 JavaScript
3.2.21. 序列 — sequence<T>
IDL sequence<T> 值由 JavaScript 数组值表示。
通过以下方式将 JavaScript 值 V 转换为 IDL sequence<T> 值:
通过以下方式将类型为 sequence<T> 的 IDL 序列值 S 转换为 JavaScript 数组对象:
-
令 n 为 S 的长度。
-
令 A 为通过表达式
[]
创建的新数组对象。 -
初始化 i 为 0。
-
当 i < n 时:
-
令 V 为 S 中索引为 i 的值。
-
令 E 为将 V 转换为 JavaScript 值的结果。
-
执行 ! CreateDataPropertyOrThrow(A, P, E)。
-
设置 i 为 i + 1。
-
-
返回 A。
3.2.21.1. 从可迭代对象创建序列
给定一个可迭代对象 iterable 和一个迭代器获取方法 method,按照以下步骤创建类型为 sequence<T> 的 IDL 值:
-
令 iteratorRecord 为 ? GetIteratorFromMethod(iterable, method)。
-
将 i 初始化为 0。
-
重复执行:
-
令 next 为 ? IteratorStepValue(iteratorRecord)。
-
如果 next 为
done ,则返回类型为 sequence<T> 且长度为 i 的 IDL 序列值,其中索引 j 处的值为 Sj。 -
将 Si 初始化为 将 next 转换为类型 T 的 IDL 值的结果。
-
将 i 设为 i + 1。
-
以下接口定义了一个序列类型的属性以及一个带有序列类型参数的操作。
[Exposed =Window ]interface Canvas {sequence <DOMString >getSupportedImageCodecs ();undefined drawPolygon (sequence <double >coordinates );sequence <double >getLastDrawnPolygon (); // ... };
在该接口的 JavaScript 实现中,使用元素类型为 String 的数组对象表示 sequence<DOMString>
,而元素类型为
Number 的数组表示 sequence<double>
。数组对象实际上是按值传递的;每次调用
getSupportedImageCodecs()
函数时,都会返回一个新的数组,而每当将数组传递给 drawPolygon
时,调用完成后不会保留对该数组的引用。
// 获取 Canvas 的实例。假设 getSupportedImageCodecs() 返回一个包含两个 DOMString 值的序列:"image/png" 和 "image/svg+xml"。 var canvas= getCanvas(); // 一个长度为 2 的数组对象。 var supportedImageCodecs= canvas. getSupportedImageCodecs(); // 结果为 "image/png"。 supportedImageCodecs[ 0 ]; // 每次调用 canvas.getSupportedImageCodecs() 时,都会返回一个新的数组对象。因此修改返回的数组不会影响下一次函数调用的返回值。 supportedImageCodecs[ 0 ] = "image/jpeg" ; // 结果为 "image/png"。 canvas. getSupportedImageCodecs()[ 0 ]; // 由于每次调用都会返回一个新的数组对象,因此此比较结果为 false。 canvas. getSupportedImageCodecs() == canvas. getSupportedImageCodecs(); // 一个数字数组... var a= [ 0 , 0 , 100 , 0 , 50 , 62.5 ]; // ...可以传递给需要 sequence<double> 的平台对象。 canvas. drawPolygon( a); // 每个元素将通过调用 ToNumber() 转换为 double。因此,下面的调用与前一个调用等效,只不过在 drawPolygon() 返回之前,会弹出 "hi"。 a= [ false , "" , { valueOf: function () { alert( "hi" ); return 100 ; } }, 0 , "50" , new Number( 62.5 )]; canvas. drawPolygon( a); // 修改传递给 drawPolygon() 的数组保证不会影响 Canvas,因为数组实际上是按值传递的。 a[ 4 ] = 20 ; var b= canvas. getLastDrawnPolygon(); alert( b[ 4 ]); // 这会弹出 "50"。
3.2.22. 异步可迭代对象 — async iterable<T>
在 JavaScript 绑定中,IDL 异步可迭代值由具有以下项的结构体表示:
-
对象,一个 JavaScript 值
-
方法,一个 JavaScript 值
-
类型,为 "
sync
" 或 "async
"
-
令 method 为 ? GetMethod(obj,
%Symbol.asyncIterator%
)。 -
如果 method 是
undefined :
3.2.22.1. 迭代异步迭代器
异步可迭代对象不能直接迭代。相反,它首先被打开以创建一个异步迭代器。异步迭代器可以被异步迭代以产生值。
-
底层记录,一个迭代器记录
-
类型参数,一个 IDL 类型,表示异步迭代器产生的值的类型
要打开一个
async iterable<T>
iterable:
-
令 iterator 为 ? GetIteratorFromMethod(iterable 的对象, iterable 的方法)。
-
如果 iterable 的类型是 "
sync
",则设置 iterator 为 CreateAsyncFromSyncIterator(iterator)。
要获取下一个值,对于异步迭代器 iterator:
-
令 nextResult 为 IteratorNext(iterator 的底层记录)。
-
如果 nextResult 是一个突然完成,则返回一个被拒绝的 promise,拒绝原因为 nextResult.[[Value]]。
-
令 nextPromise 为一个已解决的 promise,解决值为 nextResult.[[Value]]。
-
返回对 nextPromise 作出反应的结果,使用以下完成步骤,给定 iterResult:
-
令 done 为 ? IteratorComplete(iterResult)。
-
如果 done 为 true:
-
返回迭代结束。
-
-
否则:
-
令 V 为 ? IteratorValue(iterResult)。
-
返回 value。
-
要关闭一个
async iterator<T>
iterator,使用 ECMAScript 值 reason:
-
令 iteratorRecord 为 iterator 的底层记录。
-
令 iteratorObj 为 iteratorRecord.[[Iterator]]。
-
令 returnMethod 为 GetMethod(iteratorObj, "
return
")。 -
如果 returnMethod 是一个突然完成,则返回一个被拒绝的 promise,拒绝原因为 returnMethod.[[Value]]。
-
如果 returnMethod 是
undefined ,则返回一个已解决的 promise,解决值为undefined
。 -
令 returnResult 为 Call(returnMethod.[[Value]], iteratorObj, « reason »)。
-
如果 returnResult 是一个突然完成,则返回一个被拒绝的 promise,拒绝原因为 returnResult.[[Value]]。
-
令 returnPromise 为一个已解决的 promise,解决值为 returnResult.[[Value]]。
-
返回对 returnPromise 作出反应的结果,使用以下完成步骤,给定 returnPromiseResult:
concatN
是一个操作,它返回一个 promise,该 promise
将使用传递给它的异步可迭代对象产生的所有字符串的串联来完成。一旦异步可迭代对象产生了 maxN 个字符串,它就会停止串联并关闭迭代器。
interface I { Promise<DOMString> concatN(async iterable<DOMString> strings, unsigned long maxN); };
concatN(iterable, maxN)
方法的步骤如下:
-
令 promise 为一个新的 promise。
-
令 result 为空字符串。
-
令 n 为 0。
-
令 iterator 为打开 iterable 的结果。
-
令 step 为将用于处理异步可迭代对象的一系列步骤:
-
调用 step。
-
返回 promise。
3.2.23. 记录 — record<K, V>
IDL record<K, V> 值由 JavaScript 对象值表示。
IDL record<…>
值 D 按如下方式转换为 JavaScript 值:
-
令 result 为 OrdinaryObjectCreate(
%Object.prototype%
)。 -
对于 D 中的每个 key → value:
-
令 jsKey 为 key 转换为 JavaScript 值。
-
令 jsValue 为 value 转换为 JavaScript 值。
-
令 created 为 ! CreateDataProperty(result, jsKey, jsValue)。
-
断言:created 是
true 。
-
-
返回 result。
将 JavaScript 值 {b: 3, a: 4}
作为
record<DOMString, double>
参数传递时,会生成 IDL 值 «[ "b
" → 3, "a
" → 4 ]»。
记录只考虑 自有 可枚举
属性,因此给定一个返回其参数的 IDL 操作
record<DOMString, double> identity(record<DOMString, double> arg)
,以下代码通过其断言:
let proto= { a: 3 , b: 4 }; let obj= { __proto__: proto, d: 5 , c: 6 } Object. defineProperty( obj, "e" , { value: 7 , enumerable: false }); let result= identity( obj); console. assert( result. a=== undefined ); console. assert( result. b=== undefined ); console. assert( result. e=== undefined ); let entries= Object. entries( result); console. assert( entries[ 0 ][ 0 ] === "d" ); console. assert( entries[ 0 ][ 1 ] === 5 ); console. assert( entries[ 1 ][ 0 ] === "c" ); console. assert( entries[ 1 ][ 1 ] === 6 );
记录键和值可以受到约束,尽管键只能在三种字符串类型之间受到约束。以下转换具有描述的结果:
值 | 传递给的类型 | 结果 |
---|---|---|
{"😞": 1}
|
record<ByteString, double>
|
TypeError
|
{"\uD83D": 1}
|
record<USVString, double>
|
«[ "\uFFFD " → 1 ]»
|
{"\uD83D": {hello: "world"}}
|
record<DOMString, double>
|
«[ "\uD83D " → 0 ]»
|
3.2.24. Promise 类型 — Promise<T>
IDL promise 类型值由 JavaScript PromiseCapability 记录表示。
通过以下方式将 JavaScript 值 V 转换为 IDL
Promise<T>
值:
-
令 promiseCapability 为 ? NewPromiseCapability(
%Promise%
)。 -
返回 promiseCapability。
将 IDL promise 类型值转换为 JavaScript 值的结果是 IDL promise 类型所表示的记录的 [[Promise]] 字段的值。
3.2.24.1. 创建和操作 Promise
要在领域 realm 中创建一个新的
Promise<T>
,请执行以下步骤:
-
令 constructor 为 realm.[[Intrinsics]].[[
%Promise%
]]。 -
返回 ? NewPromiseCapability(constructor)。
要在领域 realm 中创建一个类型为
Promise<T>
的被拒绝的 promise,原因为 r(一个 JavaScript 值),请执行以下步骤:
-
令 constructor 为 realm.[[Intrinsics]].[[
%Promise%
]]。 -
令 promiseCapability 为 ? NewPromiseCapability(constructor)。
-
返回 promiseCapability。
要用 x(类型为 T 的值)解决一个
Promise<T>
p,请执行以下步骤:
要对一个
Promise<T>
promise 作出反应,给定一组或两组要执行的步骤,涵盖
promise 完成、拒绝或两者兼有的情况,请执行以下步骤:
-
令 onFulfilledSteps 为给定参数 V 的以下步骤:
-
令 value 为将 V 转换为类型为 T 的 IDL 值的结果。
-
如果有一组在 promise 完成时要运行的步骤,则令 result 为执行它们的结果,如果 T 不是
undefined
,则给定 value。否则,令 result 为 value。 -
返回 result,转换为 JavaScript 值。
-
-
令 onFulfilled 为 CreateBuiltinFunction(onFulfilledSteps, « »):
-
令 onRejectedSteps 为给定参数 R 的以下步骤:
-
如果有一组在 promise 被拒绝时要运行的步骤,则令 result 为执行它们的结果,给定 reason。否则,令 result 为一个被拒绝的 promise,原因为 reason。
-
返回 result,转换为 JavaScript 值。
-
令 onRejected 为 CreateBuiltinFunction(onRejectedSteps, « »):
-
令 constructor 为 promise.[[Promise]].[[Realm]].[[Intrinsics]].[[
%Promise%
]]。 -
令 newCapability 为 ? NewPromiseCapability(constructor)。
注意:并非所有调用者都会使用返回的
Promise
。实现可能希望在这些情况下避免创建 newCapability。 -
执行 PerformPromiseThen(promise.[[Promise]], onFulfilled, onRejected, newCapability)。
-
返回 newCapability。
注意:此算法的行为与 promise.then()
方法非常相似。特别是,如果步骤返回类型为 U 或
Promise<U>
的值,则此算法也会返回一个
Promise<U>
。
要在
Promise<T>
promise 完成时执行某些步骤 steps(这些步骤接受类型为 T 的值),请执行以下步骤:
-
返回对 promise 作出反应的结果:
-
如果 promise 以值 v 完成,则:
-
用 v 执行 steps。
-
-
要在
Promise<T>
promise 被拒绝时执行某些步骤 steps(这些步骤接受一个 JavaScript 值),请执行以下步骤:
-
返回对 promise 作出反应的结果:
-
如果 promise 因原因 r 而被拒绝,则:
-
用 r 执行 steps。
-
-
要等待所有
Promise<T>
值 promises 的列表,其中成功步骤 successSteps 接受 T 值的列表,失败步骤 failureSteps
接受拒绝原因 any
值,请执行以下步骤:
-
令 fullfilledCount 为 0。
-
令 rejected 为 false。
-
令 rejectionHandlerSteps 为给定 arg 的以下步骤:
-
如果 rejected 为 true,则中止这些步骤。
-
设置 rejected 为 true。
-
给定 arg 执行 failureSteps。
-
-
令 rejectionHandler 为 CreateBuiltinFunction(rejectionHandlerSteps, « »):
-
令 total 为 promises 的大小。
-
如果 total 为 0,则:
-
将微任务排队以执行给定 « » 的 successSteps。
-
返回。
-
-
令 index 为 0。
-
令 result 为包含 total 个 null 值的列表。
-
对于 promises 中的每个 promise:
-
令 promiseIndex 为 index。
-
令 fulfillmentHandler 为给定 arg 的以下步骤:
-
设置 result[promiseIndex] 为 arg。
-
设置 fullfilledCount 为 fullfilledCount + 1。
-
如果 fullfilledCount 等于 total,则执行给定 result 的 successSteps。
-
-
令 fulfillmentHandler 为 CreateBuiltinFunction(fulfillmentHandler, « »):
-
执行 PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler)。
-
设置 index 为 index + 1。
-
要获取一个用于等待所有
Promise<T>
值 promises 的列表和领域 realm 的 promise,请执行以下步骤:
-
令 promise 为在 realm 中类型为
Promise<sequence<T>>
的一个新的 promise。 -
令 successSteps 为给定 results 的以下步骤:
-
用 results 解决 promise。
-
-
令 failureSteps 为给定 reason 的以下步骤:
-
用 reason 拒绝 promise。
-
-
用 promises、successSteps 和 failureSteps 等待所有。
-
返回 promise。
当您希望聚合多个 promise 的结果,然后从中生成另一个 promise 时,此定义非常有用,其方式与 Promise.all()
函数对 JavaScript 代码的作用相同。如果您不需要生成另一个 promise,那么等待所有可能更好。
Promise<T>
promise,请将 promise.[[Promise]].[[PromiseIsHandled]] 设置为 true。
此定义对于您期望其拒绝通常会被忽略的 promise 非常有用;它确保此类 promise 不会导致 unhandledrejection
事件。最常见的用例是 promise 属性,Web 开发人员可能会也可能不会查阅这些属性。例如 writableStreamWriter.closed
promise。
3.2.24.2. 示例
delay
是一个操作,它返回一个将在若干毫秒后完成的 promise。
它演示了如何用一行散文简单地解决一个 promise。
interface I {Promise <undefined >delay (unrestricted double ms ); };
validatedDelay
操作与 delay
函数非常相似,只是它会验证其参数。
这显示了如何在开始任何异步操作之前使用被拒绝的 promise 来表示立即失败。
interface I {Promise <undefined >validatedDelay (unrestricted double ms ); };
validatedDelay(ms)
方法的步骤如下:
-
令 taskSource 为某个合适的任务源。
-
如果 ms 是 NaN,则返回在 realm 中一个被拒绝的 promise,拒绝原因为
TypeError
。 -
如果 ms < 0,则返回在 realm 中一个被拒绝的 promise,拒绝原因为
RangeError
。 -
令 p 为在 realm 中的一个新的 promise。
-
并行运行以下步骤:
-
返回 p。
addDelay
是一个操作,它在 promise 敲定和返回的 promise 敲定之间添加额外的延迟毫秒数。
interface I {Promise <any >addDelay (Promise <any >promise ,unrestricted double ms ); };
addDelay(ms, promise)
方法的步骤如下:
environment.ready
是一个属性,它指示某个环境的某个部分(例如 DOM 文档)何时变为“就绪”。
它演示了如何编码环境异步性。
interface Environment {readonly attribute Promise <undefined >ready ; };
每个 Environment
对象都必须有一个就绪 promise,它是一个
Promise<undefined>
。
ready
属性获取器的步骤如下:
-
返回此对象的就绪 promise。
要在领域 realm 中创建一个 Environment
对象,请执行以下步骤:
-
令 taskSource 为某个合适的任务源。
-
令 environment 为在 realm 中的新的
Environment
对象。 -
将 environment 的就绪 promise 设置为在 realm 中的一个新的 promise。
-
并行运行以下步骤:
-
执行一些异步工作。
-
如果 environment 成功就绪,则在 taskSource 上将任务排队以解决 environment 的就绪 promise。
-
如果 environment 未能就绪,则在 taskSource 上将任务排队以用 "
NetworkError
"DOMException
拒绝 environment 的就绪 promise。
-
-
返回 environment。
addBookmark
是一个操作,它请求用户将当前网页添加为书签。
它源自一些迭代设计工作,并演示了一个更真实的场景,即利用环境异步性以及立即拒绝。
interface I {Promise <undefined >addBookmark (); };
addBookmark()
方法的步骤如下:
-
令 taskSource 为某个合适的任务源。
-
如果此方法不是由于显式用户操作而调用的,则返回一个被拒绝的 promise,拒绝原因为 "
SecurityError
"DOMException
。 -
如果文档的操作模式是独立的,则返回一个被拒绝的 promise,拒绝原因为 "
NotSupportedError
"DOMException
。 -
令 promise 为一个新的 promise。
-
令 info 为获取 Web 应用程序元数据的结果。
-
并行运行以下步骤:
-
使用 info,并以用户代理特定的方式,允许最终用户选择是否要添加书签。
-
如果最终用户中止添加书签的请求(例如,他们按了 Escape 键或“取消”按钮),则在 taskSource 上将任务排队以用 "
AbortError
"DOMException
拒绝 promise。
-
-
-
返回 promise。
在 [SERVICE-WORKERS]
中的几个地方使用了获取一个用于等待所有。batchRequest
演示了其用途的简化版本。
它以 URL 的序列作为输入,并返回一个
promise,该 promise 用于通过获取相应 URL 创建的 Response
对象的序列。
如果任何获取失败,它将返回一个被拒绝的 promise,拒绝原因为该失败。
interface I {Promise <sequence <Response >>batchRequest (sequence <USVString >urls ); };
batchRequest(urls)
方法的步骤如下:
-
令 responsePromises 为 « »。
-
对于 urls 中的每个 url:
-
令 p 为获取一个用于等待所有并传入 responsePromises 的结果。
-
返回 p。
3.2.25. 联合类型
IDL 联合类型值由 JavaScript 值表示,这些值对应于联合的成员类型。
将 JavaScript 值 V 转换为 IDL 联合类型值的步骤如下:
-
如果联合类型包含 undefined 且 V 是
undefined ,则返回唯一的undefined
值。 -
如果 V 是
null 或undefined ,则: -
如果 V 是平台对象,则:
-
如果 V 是一个对象,V 具有 [[ArrayBufferData]] 内部插槽,并且 IsSharedArrayBuffer(V) 为 false,则:
-
如果 types 包含
ArrayBuffer
,则返回将 V 转换为ArrayBuffer
的结果。 -
如果 types 包含
object
,则返回引用对象 V 的 IDL 值。
-
-
如果 V 是一个对象,V 具有 [[ArrayBufferData]] 内部插槽,并且 IsSharedArrayBuffer(V) 为 true,则:
-
如果 types 包含
SharedArrayBuffer
,则返回将 V 转换为SharedArrayBuffer
的结果。 -
如果 types 包含
object
,则返回引用对象 V 的 IDL 值。
-
-
如果 IsCallable(V) 为 true,则:
-
如果 V 是一个对象,则:
-
如果 types 包含异步可迭代类型,则
-
如果 types 包含序列类型,则
-
令 method 为 ? GetMethod(V,
%Symbol.iterator%
)。 -
如果 method 不是
undefined ,则返回从 V 和 method 创建该类型的序列的结果。
-
-
如果 types 包含冻结数组类型,则
-
令 method 为 ? GetMethod(V,
%Symbol.iterator%
)。 -
如果 method 不是
undefined ,则返回从 V 和 method 创建该类型的冻结数组的结果。
-
-
如果 types 包含
object
,则返回引用对象 V 的 IDL 值。
-
-
如果 V 是布尔值,则:
-
如果 V 是数字,则:
-
如果 V 是 BigInt,则:
IDL 联合类型值根据本节(§ 3.2 JavaScript 类型映射)中描述的转换 IDL 联合类型值的特定类型的规则转换为 JavaScript 值。
3.2.26. 缓冲区源类型
IDL ArrayBuffer
的值由相应 JavaScript 类的对象表示。
如果它没有与 [AllowResizable
]
扩展属性关联,则它只能由 JavaScript ArrayBuffer
对象 V 支持,其中 IsResizableArrayBuffer(V) 为 false。
IDL SharedArrayBuffer
的值由相应 JavaScript 类的对象表示。
如果它没有与 [AllowResizable
]
扩展属性关联,则它只能由 JavaScript SharedArrayBuffer
对象 V 支持,其中 IsResizableArrayBuffer(V) 为 false。
IDL 缓冲区视图类型的值由相应 JavaScript 类的对象表示,但对这些对象有以下附加限制。
- 如果该类型没有与 [
AllowResizable
] 或 [AllowShared
] 扩展属性(如果适用)关联,则它们只能由 JavaScriptArrayBuffer
对象 V 支持,其中 IsResizableArrayBuffer(V) 为 false。 - 如果该类型与 [
AllowResizable
] 扩展属性关联,但没有与 [AllowShared
] 扩展属性(如果适用)关联,则它们只能由 JavaScriptArrayBuffer
对象支持。 - 如果该类型与 [
AllowShared
] 扩展属性关联,但没有与 [AllowResizable
] 扩展属性关联,则它们只能由 JavaScriptArrayBuffer
和SharedArrayBuffer
对象 V 支持,其中 IsResizableArrayBuffer(V) 为 false。 - 如果该类型与 [
AllowResizable
] 和 [AllowShared
] 扩展属性关联,则它们可以由任何 JavaScriptArrayBuffer
或SharedArrayBuffer
对象支持。
JavaScript 值 V 通过运行以下算法转换为 IDL ArrayBuffer
值:
-
如果 IsSharedArrayBuffer(V) 为 true,则抛出
TypeError
。 -
如果转换不是到与 [
AllowResizable
] 扩展属性关联的 IDL 类型,并且 IsResizableArrayBuffer(V) 为 true, 则抛出TypeError
。 -
返回引用与 V 相同对象的 IDL
ArrayBuffer
值。
JavaScript 值 V 通过运行以下算法转换为 IDL SharedArrayBuffer
值:
-
如果 IsSharedArrayBuffer(V) 为 false,则抛出
TypeError
。 -
如果转换不是到与 [
AllowResizable
] 扩展属性关联的 IDL 类型,并且 IsResizableArrayBuffer(V) 为 true, 则抛出TypeError
。 -
返回引用与 V 相同对象的 IDL
SharedArrayBuffer
值。
JavaScript 值 V 通过运行以下算法转换为 IDL DataView
值:
-
如果转换不是到与 [
AllowShared
] 扩展属性关联的 IDL 类型,并且 IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) 为 true, 则抛出TypeError
。 -
如果转换不是到与 [
AllowResizable
] 扩展属性关联的 IDL 类型,并且 IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) 为 true, 则抛出TypeError
。 -
返回引用与 V 相同对象的 IDL
DataView
值。
JavaScript 值 V 通过运行以下算法转换为 IDL Int8Array
、
Int16Array
、
Int32Array
、
Uint8Array
、
Uint16Array
、
Uint32Array
、
Uint8ClampedArray
、
BigInt64Array
、
BigUint64Array
、
Float16Array
、
Float32Array
或 Float64Array
值:
-
令 T 为 V 正在转换到的 IDL 类型。
-
如果 V 不是对象, 或者 V 没有 [[TypedArrayName]] 内部槽,其值等于 T 的名称, 则抛出
TypeError
。 -
如果转换不是到与 [
AllowShared
] 扩展属性关联的 IDL 类型,并且 IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) 为 true, 则抛出TypeError
。 -
如果转换不是到与 [
AllowResizable
] 扩展属性关联的 IDL 类型,并且 IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) 为 true, 则抛出TypeError
。 -
返回引用与 V 相同对象的类型为 T 的 IDL 值。
ArrayBuffer
:
-
令 jsArrayBuffer 为 ? AllocateArrayBuffer(realm.[[Intrinsics]].[[
%ArrayBuffer%
]], bytes 的长度)。 -
令 arrayBuffer 为将 jsArrayBuffer 转换为类型为
ArrayBuffer
的 IDL 值的结果。 -
将 bytes 写入 arrayBuffer。
-
返回 arrayBuffer。
SharedArrayBuffer
:
-
令 jsSharedArrayBuffer 为 ? AllocateSharedArrayBuffer(realm.[[Intrinsics]].[[
%SharedArrayBuffer%
]], bytes 的长度)。 -
令 sharedArrayBuffer 为将 jsSharedArrayBuffer 转换为类型为
SharedArrayBuffer
的 IDL 值的结果。 -
将 bytes 写入 sharedArrayBuffer。
-
返回 sharedArrayBuffer。
ArrayBufferView
类型:
-
令 arrayBuffer 为从 bytes 在 realm 中创建一个
ArrayBuffer
的结果。 -
令 jsArrayBuffer 为将 arrayBuffer 转换为 JavaScript 值的结果。
-
令 constructor 为 realm.[[Intrinsics]] 中正在创建的
ArrayBufferView
类型的适当构造函数。 -
返回将 jsView 转换为给定类型的结果。
-
令 jsBufferSource 为将 bufferSource 转换为 JavaScript 值的结果。
-
令 jsArrayBuffer 为 jsBufferSource。
-
令 offset 为 0。
-
令 length 为 0。
-
如果 jsBufferSource 有一个 [[ViewedArrayBuffer]] 内部槽,则:
-
将 jsArrayBuffer 设置为 jsBufferSource.[[ViewedArrayBuffer]]。
-
将 offset 设置为 jsBufferSource.[[ByteOffset]]。
-
将 length 设置为 jsBufferSource.[[ByteLength]]。
-
-
否则:
-
断言:jsBufferSource 是一个
ArrayBuffer
或SharedArrayBuffer
对象。 -
将 length 设置为 jsBufferSource.[[ArrayBufferByteLength]]。
-
-
如果 IsDetachedBuffer(jsArrayBuffer) 为 true,则返回空的字节序列。
-
对于范围 offset 到 offset + length − 1(含)中的 i,将 bytes[i − offset] 设置为 GetValueFromBuffer(jsArrayBuffer, i, Uint8, true, Unordered)。
-
返回 bytes。
-
令 jsBufferSource 为将 bufferSource 转换为 JavaScript 值的结果。
-
如果 jsBufferSource 有一个 [[ViewedArrayBuffer]] 内部槽,则返回 jsBufferSource.[[ByteLength]]。
-
返回 jsBufferSource.[[ArrayBufferByteLength]]。
-
如果 bufferSource 是一个缓冲区类型实例,则返回 bufferSource。
-
令 jsBufferView 为将 bufferSource 转换为 JavaScript 值的结果。
-
令 jsBuffer 为 jsBufferView.[[ViewedArrayBuffer]]。
-
如果 IsSharedArrayBuffer(jsBuffer) 为 false,则返回将 jsBuffer 转换为类型为
ArrayBuffer
的 IDL 值的结果。 -
返回将 jsBuffer 转换为类型为
SharedArrayBuffer
的 IDL 值的结果。
-
令 jsArrayBuffer 为将 arrayBuffer 转换为 JavaScript 值的结果。
-
断言:bytes 的长度 ≤ jsArrayBuffer.[[ArrayBufferByteLength]] − startingOffset。
-
对于范围 startingOffset 到 startingOffset + bytes 的长度 − 1(含)中的 i,执行 SetValueInBuffer(jsArrayBuffer, i, Uint8, bytes[i - startingOffset], true, Unordered)。
ArrayBufferView
view,可选地给定一个startingOffset(默认为 0):
-
令 jsView 为将 view 转换为 JavaScript 值的结果。
-
断言:bytes 的长度 ≤ jsView.[[ByteLength]] − startingOffset。
-
令 arrayBuffer 为将 jsView.[[ViewedArrayBuffer]] 转换为类型为
ArrayBuffer
的 IDL 值的结果。 -
将 bytes 写入 arrayBuffer,其中 startingOffset 设置为 jsView.[[ByteOffset]] + startingOffset。
SharedArrayBuffer
对象,则尤其如此。
对于非共享情况,更推荐的模式是如果可能,首先传输 ArrayBuffer
,以确保写入不会与其他修改重叠,然后根据需要将新的
ArrayBuffer
实例提供给作者代码。或者,您可以获取缓冲区源持有的字节副本,修改这些字节,然后使用它们创建一个新的 ArrayBuffer
或 ArrayBufferView
以返回给作者代码。
ArrayBuffer
arrayBuffer:
-
令 jsArrayBuffer 为将 arrayBuffer 转换为 JavaScript 值的结果。
-
执行 ? DetachArrayBuffer(jsArrayBuffer)。
如果 jsArrayBuffer 有一个不为 undefined 的
[[ArrayBufferDetachKey]],例如 WebAssembly.Memory
的 buffer
属性的值,则会抛出异常。[WASM-JS-API-1]
分离一个已经分离的缓冲区是一个空操作。
-
令 jsArrayBuffer 为将 bufferSource 转换为 JavaScript 值的结果。
-
如果 jsArrayBuffer 有一个 [[ViewedArrayBuffer]] 内部槽,则将 jsArrayBuffer 设置为 jsArrayBuffer.[[ViewedArrayBuffer]]。
-
返回 IsDetachedBuffer(jsArrayBuffer)。
-
令 jsArrayBuffer 为将 bufferSource 转换为 JavaScript 值的结果。
-
如果 jsArrayBuffer 有一个 [[ViewedArrayBuffer]] 内部槽,则将 jsArrayBuffer 设置为 jsArrayBuffer.[[ViewedArrayBuffer]]。
-
如果 IsSharedArrayBuffer(jsArrayBuffer) 为 true,则返回 false。
-
如果 IsDetachedBuffer(jsArrayBuffer) 为 true,则返回 false。
-
如果 jsArrayBuffer.[[ArrayBufferDetachKey]] 不为
undefined ,则返回 false。 -
返回 true。
ArrayBuffer
arrayBuffer,可选地给定一个领域 targetRealm:
-
令 jsArrayBuffer 为将 arrayBuffer 转换为 JavaScript 值的结果。
-
如果 IsDetachedBuffer(jsArrayBuffer) 为 false,则抛出
TypeError
。 -
令 arrayBufferData 为 jsArrayBuffer.[[ArrayBufferData]]。
-
令 arrayBufferByteLength 为 jsArrayBuffer.[[ArrayBufferByteLength]]。
-
执行 ? DetachArrayBuffer(jsArrayBuffer)。
-
如果未给定 targetRealm,则令 targetRealm 为当前领域。
-
令 jsTransferred 为 ? AllocateArrayBuffer(targetRealm.[[Intrinsics]].[[
%ArrayBuffer%
]], 0)。 -
将 jsTransferred.[[ArrayBufferData]] 设置为 arrayBufferData。
-
将 jsTransferred.[[ArrayBufferByteLength]] 设置为 arrayBufferByteLength。
-
返回将 jsTransferred 转换为类型为
ArrayBuffer
的 IDL 值的结果。
-
arrayBuffer 不能被分离,原因在该算法的定义中解释;
-
arrayBuffer 已经分离;
-
在 realm 中无法分配足够的内存。通常只有在 realm 与分配 arrayBuffer 的代理集群不同时才会出现这种情况。如果它们在同一个代理集群中,则实现将仅更改后备指针以获得相同的可观察结果,同时具有更好的性能且无需分配。
3.2.27. 冻结数组 — FrozenArray<T>
冻结数组类型的值由冻结的 JavaScript Array 对象引用表示。
JavaScript 值 V 通过运行以下算法转换为 IDL FrozenArray<T> 值:
-
令 values 为将 V 转换为 IDL 类型 sequence<T> 的结果。
-
返回从 values 创建冻结数组的结果。
要从类型为 T 的值序列创建冻结数组,请执行以下步骤:
-
令 array 为将类型为 T 的值序列转换为 JavaScript 值的结果。
-
执行 ! SetIntegrityLevel(array, "
frozen
")。 -
返回 array。
将 IDL FrozenArray<T> 值转换为 JavaScript 值的结果是表示对 IDL FrozenArray<T> 所表示的相同对象的引用的 Object 值。
3.2.27.1. 从可迭代对象创建冻结数组
要给定一个可迭代对象 iterable 和一个迭代器获取器 method 来创建类型为 FrozenArray<T> 的 IDL 值,请执行以下步骤:
-
令 values 为从 iterable 和 method 创建类型为 sequence<T> 的序列的结果。
-
返回从 values 创建冻结数组的结果。
3.2.28. 可观察数组 — ObservableArray<T>
可观察数组类型的值由可观察数组奇异对象表示。
与通常的转换算法不同,可观察数组类型作为属性获取器和属性设置器算法的一部分具有特殊的处理方式。
在 JavaScript 绑定中,表示平台对象的 JavaScript 对象对于可观察数组类型的每个常规属性都有一个后备可观察数组奇异对象。这些对象作为定义属性算法的一部分进行创建和管理。
-
令 oa 为 obj 针对 attribute 的后备可观察数组奇异对象。
-
返回 oa.[[ProxyHandler]].[[BackingList]]。
3.3. 扩展属性
本节定义了许多扩展属性,它们的存在会影响 JavaScript 绑定。
3.3.1. [AllowResizable]
如果 [AllowResizable
]
扩展属性出现在缓冲区类型上,它会创建一个新的
IDL 类型,允许相应的 JavaScript ArrayBuffer
或 SharedArrayBuffer
对象可调整大小。
如果 [AllowResizable
]
扩展属性出现在缓冲区视图类型之一上,并且
[AllowShared
]
扩展属性不存在,它会创建一个新的 IDL 类型,允许
缓冲区视图类型由可调整大小的 JavaScript ArrayBuffer
支持,而不仅仅是固定长度的 ArrayBuffer
。
如果 [AllowResizable
]
扩展属性和
[AllowShared
]
扩展属性都出现在缓冲区视图类型之一上,它会创建一个新的
IDL 类型,允许缓冲区
视图类型额外由可增长的 JavaScript SharedArrayBuffer
支持。
[AllowResizable
]
扩展属性必须不带参数。
不是缓冲区源类型的类型不得与 [AllowResizable
]
扩展属性关联。
有关使用 [AllowResizable
]
所带来的具体要求,请参阅 § 3.2.26 缓冲区源类型中将 JavaScript 值转换为 IDL 缓冲区源类型的规则。
有关 [AllowResizable
]
和 [AllowShared
]
的用法示例,请参阅 § 3.3.2 [AllowShared] 中的示例。
3.3.2. [AllowShared]
如果 [AllowShared
]
扩展属性出现在缓冲区视图类型之一上,它会
创建一个新的 IDL 类型,允许对象由 SharedArrayBuffer
支持,而不仅仅是
ArrayBuffer
。
[AllowShared
]
扩展属性必须不带参数。
不是缓冲区视图类型的类型不得与 [AllowShared
]
扩展属性关联。
有关使用 [AllowShared
]
所带来的具体要求,请参阅 § 3.2.26
缓冲区源类型中将 JavaScript 值转换为 IDL 缓冲区视图类型的规则。
3.3.3. [Clamp]
如果 [Clamp
] 扩展属性出现在整数类型之一上,它将创建一个新的 IDL
类型,当 JavaScript Number 转换为该 IDL 类型时,超出范围的值将被限制在有效值的范围内,而不是使用模运算符(ToInt32、ToUint32等)。
使用 [Clamp
]
扩展属性注释的类型不得出现在 只读属性中。不得将某种类型同时与 [Clamp
] 和 [EnforceRange
]
扩展属性关联。非整数类型的类型不得与 [Clamp
] 扩展属性关联。
有关将 JavaScript 值转换为各种 IDL 整数类型的规则,请参见 § 3.2.4 整数类型,了解使用 [Clamp
] 所涉及的具体要求。
在以下IDL 片段中,声明了两个操作,它们接受三个 octet
参数;一个在所有三个参数上使用了 [Clamp
] 扩展属性,而另一个没有:
[Exposed =Window ]interface GraphicsContext {undefined setColor (octet red ,octet green ,octet blue );undefined setColorClamped ([Clamp ]octet red , [Clamp ]octet green , [Clamp ]octet blue ); };
调用 setColorClamped
并传入超出 octet
范围的
Number 值时,这些值将被限制在 [0, 255] 范围内。
// 获取一个 GraphicsContext 实例。 var context= getGraphicsContext(); // 调用未使用 [Clamp] 的版本会使用 ToUint8 将 Number 值强制转换为 octet。 // 这相当于调用 setColor(255, 255, 1)。 context. setColor( - 1 , 255 , 257 ); // 使用一些超出范围的值调用 setColorClamped。 // 这相当于调用 setColorClamped(0, 255, 255)。 context. setColorClamped( - 1 , 255 , 257 );
3.3.4. [CrossOriginIsolated]
如果 [CrossOriginIsolated
]
扩展属性出现在 接口、部分接口、接口混合、部分接口混合、回调接口、命名空间、部分命名空间、接口成员、接口混合成员或命名空间成员上,它表明该构造仅在其暴露于跨源隔离能力为真的环境内。
[CrossOriginIsolated
]
扩展属性必须 不带参数。
如果 [CrossOriginIsolated
]
出现在重载的 操作上,则它必须出现在所有重载上。
[CrossOriginIsolated
]
扩展属性不得同时出现在
注意:这是因为在成员的包含定义也使用 [CrossOriginIsolated
]
扩展属性进行注释时,在该成员上添加 [CrossOriginIsolated
]
扩展属性不会进一步限制该成员的暴露。
没有 [CrossOriginIsolated
]
扩展属性的接口不得继承
另一个确实指定了 [CrossOriginIsolated
]
的接口。
以下 IDL 片段定义了一个接口,其中一个操作可从所有上下文执行,另外两个仅可从跨域隔离的上下文执行。
[Exposed =Window ]interface ExampleFeature { // 此调用将在所有上下文中成功。Promise <Result >calculateNotSoSecretResult (); // 此操作不会暴露给非隔离上下文。在此类上下文中, // ExampleFeature.prototype 上将没有 "calculateSecretResult" 属性。 [CrossOriginIsolated ]Promise <Result >calculateSecretResult (); // 此处同样适用:该属性不会暴露给非隔离上下文, // 在此类上下文中,ExampleFeature.prototype 上将没有 "secretBoolean" 属性。 [CrossOriginIsolated ]readonly attribute boolean secretBoolean ; }; // HighResolutionTimer 不会暴露在非隔离上下文中,其成员也不会。 // 在此类上下文中,Window 上将没有 "HighResolutionTimer" 属性。 [Exposed =Window ,CrossOriginIsolated ]interface HighResolutionTimer {DOMHighResTimeStamp getHighResolutionTime (); }; // 下面定义的接口混入成员永远不会暴露在非隔离上下文中, // 无论包含它们的接口是否如此。也就是说,在非隔离上下文中, // ExampleFeature.prototype 上将没有 "snap" 属性。 [CrossOriginIsolated ]interface mixin Snapshotable {Promise <boolean >snap (); };ExampleFeature includes Snapshotable ; // 另一方面,以下接口混入成员在由不具有 // [CrossOriginIsolated] 扩展属性的主机接口包含时,将暴露给非隔离上下文。 // 也就是说,在非隔离上下文中,ExampleFeature.prototype 上将具有 "log" 属性。interface mixin Loggable {Promise <boolean >log (); };ExampleFeature includes Loggable ;
3.3.5. [Default]
如果 [Default
] 扩展属性 出现在
常规操作
上,则表示当操作被调用时,必须执行适当的 默认方法步骤。
[Default
]
扩展属性不得用于没有定义 默认方法步骤 的任何其他东西。
例如,适合在 toJSON
常规操作 上使用 [Default
] 扩展属性:
[Exposed =Window ]interface Animal {attribute DOMString name ;attribute unsigned short age ; [Default ]object toJSON (); }; [Exposed =Window ]interface Human :Animal {attribute Dog ?pet ; [Default ]object toJSON (); }; [Exposed =Window ]interface Dog :Animal {attribute DOMString ?breed ; };
在 JavaScript 语言绑定中,Animal
、Human
和(通过继承)Dog
对象上将存在一个
toJSON()
方法:
// 获取 Human 的一个实例。 var alice= getHuman(); // 计算结果是一个类似这样的对象(注意 "pet" 此时仍持有 Dog 的实例): // // { // name: "Alice", // age: 59, // pet: Dog // } alice. toJSON(); // 计算结果是一个类似这样的对象(注意 "breed" 缺失了, // 因为 Dog 接口没有使用默认的 toJSON 步骤): // // { // name: "Tramp", // age: 6 // } alice. pet. toJSON(); // 计算结果是一个类似这样的字符串: // '{"name":"Alice","age":59,"pet":{"name":"Tramp","age":6}}' JSON. stringify( alice);
3.3.6. [EnforceRange]
如果 [EnforceRange
]
扩展属性 出现在 整数类型 上,则它创建一个新的 IDL
类型,使得当 JavaScript 数字转换为 IDL 类型时,超出范围的值将导致抛出异常,而不是使用带有取模运算的操作符 (ToInt32、ToUint32 等) 转换为有效值。该数字将在进行范围检查之前向零取整。
[EnforceRange
]
扩展属性必须 不带参数。
带有 [EnforceRange
]
扩展属性的类型不能出现在 只读 属性中。类型不能同时关联
[Clamp
] 和 [EnforceRange
]
扩展属性。非 整数类型 的类型不能关联
[EnforceRange
]
扩展属性。
请参阅 § 3.2 JavaScript 类型映射 中有关将 JavaScript 值转换为各种 IDL 整数类型的规则,了解使用 [EnforceRange
]
的具体要求。
在下面的 IDL 片段中,声明了两个
操作,它们接受三个 octet
参数;其中一个使用 [EnforceRange
]
扩展属性,另一个没有:
[Exposed =Window ]interface GraphicsContext {undefined setColor (octet red ,octet green ,octet blue );undefined setColorEnforcedRange ([EnforceRange ]octet red , [EnforceRange ]octet green , [EnforceRange ]octet blue ); };
在 IDL 的 JavaScript 实现中,调用 setColorEnforcedRange
并传入超出 octet
范围的数字值时,将会抛出异常。
// 获取 GraphicsContext 的一个实例。 var context= getGraphicsContext(); // 调用非 [EnforceRange] 版本时,使用 ToUint8 将数字强制转换为 octets。 // 这相当于调用 setColor(255, 255, 1)。 context. setColor( - 1 , 255 , 257 ); // 调用 setColorEnforcedRange 时,数字将向零舍入。 // 这相当于调用 setColor(0, 255, 255)。 context. setColorEnforcedRange( - 0.9 , 255 , 255.2 ); // 由于即使在舍入后,第一和第三个参数值仍然超出范围, // 因此以下操作将抛出 TypeError。 context. setColorEnforcedRange( - 1 , 255 , 256 );
3.3.7. [Exposed]
当 [Exposed
] 扩展属性 出现在
接口、部分接口、接口混合、部分接口混合、回调接口、命名空间、部分命名空间或单个接口成员、接口混合成员、命名空间成员时,它表示该构造在该特定的一组全局接口上公开。
[Exposed
] 扩展属性必须接受一个标识符、接受一个标识符列表或接受一个通配符。
提及的每个标识符都必须是某个接口的全局名称并且是唯一的。
自身公开集可以是一个有序集合或特殊值 *
,定义如下:
- 如果 [
Exposed
] 扩展属性 带有标识符 I - 如果 [
Exposed
] 扩展属性 带有标识符列表 I - 如果 [
Exposed
] 扩展属性 带有通配符 -
自身公开集 是
*
。
[Exposed=*]
需要谨慎使用。它仅适用于 API 不公开重要新功能的情况。如果 API 可能在某些环境中受到限制或禁用,建议显式列出全局接口。
公开集交集 对于构造 C 和接口或 null H 定义如下:
如果 [Exposed
]
出现在一个重载的 操作上, 那么它必须在所有重载上相同地出现。
[Exposed
]
扩展属性不得同时在接口成员、接口混入成员或命名空间成员上,以及在该成员声明所在的部分接口、部分接口混入或部分命名空间定义上指定。
注意:这是因为在部分接口、部分接口混入或部分命名空间上添加
[Exposed
] 扩展属性是为其每个成员添加注解的简写。
如果 [Exposed
]
出现在部分接口或部分命名空间上,
那么该部分的自身暴露集必须是该部分的原始接口或命名空间的暴露集的子集。
如果 [Exposed
]
出现在接口或命名空间成员上,
那么该成员的暴露集必须是其所属的接口或命名空间的暴露集的子集。
如果 [Exposed
]
同时出现在部分接口混入及其原始接口混入上,
那么该部分接口混入的自身暴露集必须是该接口混入的自身暴露集的子集。
如果 [Exposed
]
同时出现在接口混入成员及其所属的接口混入上,
那么该接口混入成员的自身暴露集必须是该接口混入的自身暴露集的子集。
如果接口 X 继承自另一个接口 Y,那么 X 的暴露集必须是 Y 的暴露集的子集。
注意:由于接口混入可以被不同的接口包含,
其成员的暴露集是包含它们的接口的函数。
如果接口混入成员、部分接口混入或
接口混入使用 [Exposed
] 扩展属性进行注解,
那么接口混入成员的暴露集是相关构造的自身暴露集与宿主接口的暴露集的交集。
否则,它是宿主接口的暴露集。
Note: 由于 JavaScript 全局对象的 相关设置对象 无法改变它是否是 安全上下文 或 跨域隔离功能,实现中决定是否为接口或接口成员创建属性的过程可以在创建初始对象时做出。
参见§ 3.7 接口、§ 3.7.5 常量、§ 3.7.6 属性、§ 3.7.7 操作,了解使用 [Exposed
] 的具体要求。
[Exposed
]
用来控制 接口、回调接口、命名空间或单个 接口成员、混入成员 或 命名空间成员 是否可以在 Workers、Worklet
、Window
或这些的任意组合中使用。
以下 IDL 片段展示了如何实现这一点:
[Exposed =Window ,Global =Window ]interface Window { // ... }; // 通过对 SharedWorkerGlobalScope 和 DedicatedWorkerGlobalScope 使用相同的标识符 Worker,可以同时在 [Exposed] 扩展属性中引用它们。 [Exposed =Worker ,Global =Worker ]interface SharedWorkerGlobalScope :WorkerGlobalScope { // ... }; [Exposed =Worker ,Global =Worker ]interface DedicatedWorkerGlobalScope :WorkerGlobalScope { // ... }; // Dimensions 可以在 workers 和主线程中使用。 [Exposed =(Window ,Worker )]interface Dimensions {constructor (double width ,double height );readonly attribute double width ;readonly attribute double height ; }; // WorkerNavigator 仅在 workers 中可用。在 workers 的全局范围中访问 WorkerNavigator 会返回其接口对象,而在主线程上这样做会抛出 ReferenceError。 [Exposed =Worker ]interface WorkerNavigator { // ... }; // Node 仅在主线程中可用。在 workers 的全局范围中访问 Node 会抛出 ReferenceError。 [Exposed =Window ]interface Node { // ... }; // MathUtils 可以在 workers 和主线程中使用。 [Exposed =(Window ,Worker )]namespace MathUtils {double someComplicatedFunction (double x ,double y ); }; // WorkerUtils 仅在 workers 中可用。在 workers 的全局范围中访问 WorkerUtils 会返回其命名空间对象,而在主线程上这样做会抛出 ReferenceError。 [Exposed =Worker ]namespace WorkerUtils {undefined setPriority (double x ); }; // NodeUtils 仅在主线程中可用。在 workers 的全局范围中访问 NodeUtils 会抛出 ReferenceError。 [Exposed =Window ]namespace NodeUtils {DOMString getAllText (Node node ); };
3.3.8. [Global]
如果 [Global
] 扩展属性出现在接口上,
它表示实现此接口的对象将用作领域中的全局对象。
- 如果 [
Global
] 扩展属性接受一个标识符 -
« 给定的标识符 »
- 如果 [
Global
] 扩展属性接受一个标识符列表 -
该标识符列表
[Global
]
扩展属性必须是上述形式之一。
注意:接口的全局名称是可以在 [Exposed
] 扩展属性中引用它的标识符。
单个名称可以在多个不同的全局接口之间共享,
从而允许接口更容易地使用 [Exposed
]
将自身同时暴露给所有这些接口。
例如,“Worker
” 用于引用几种不同类型的与线程相关的全局接口。
对于这些全局接口, 原型链的结构以及与接口成员对应的属性将如何反映在原型对象上, 将不同于其他接口。具体来说:
所有领域都有一个全局原型链是否可变布尔值, 它可以在创建领域时设置。 它的值在领域的生命周期内不能更改。 默认情况下设置为 false。
这允许 ShadowRealm
全局对象具有可变原型。
将命名属性放在原型链中的对象上, 是为了使变量声明和裸字赋值 将用全局对象本身的属性来遮蔽命名属性。
将与接口成员对应的属性放在对象本身上, 意味着像下面这样的常用特性检测方法将起作用:
var indexedDB= window. indexedDB|| window. webkitIndexedDB|| window. mozIndexedDB|| window. msIndexedDB; var requestAnimationFrame= window. requestAnimationFrame|| window. mozRequestAnimationFrame|| ...;
由于 JavaScript 中处理变量声明的方式,
上面的代码将导致 window.indexedDB
和
window.requestAnimationFrame
求值为
-
该接口不得定义命名属性设置器。
-
该接口不得定义构造函数操作。
-
该接口不得同时使用 [
LegacyOverrideBuiltIns
] 扩展属性进行声明。 -
该接口不得继承自另一个带有 [
LegacyOverrideBuiltIns
] 扩展属性的接口。 -
任何其他接口不得继承自它。
如果 [Global
]
在部分接口定义上指定,
则该部分接口定义必须是接口定义中定义命名属性获取器的部分。
[Global
] 扩展属性不得用于在同一领域中可以有多个对象实现它的接口。
注意:这是因为暴露命名属性的命名属性对象位于原型链中, 让多个对象的命名属性暴露在所有这些对象都继承的对象上是没有意义的。
如果一个接口使用 [Global
]
扩展属性进行声明,
那么在该接口中,具有相同标识符的成员不得超过一个。
在这些接口中,字符串化器也不得超过一个,可迭代声明、异步可迭代声明、类映射声明或类集合声明也不得超过一个。
注意:这是因为接口的所有成员都被扁平化到实现该接口的对象上。
有关使用 [Global
] 对命名属性的具体要求,请参阅
§ 3.7.4 命名属性对象,
有关与接口成员对应的属性位置的要求,请参阅 § 3.7.5 常量、§ 3.7.6 属性和§ 3.7.7 操作。
Window
接口将 frames 作为属性暴露在 Window
对象上。由于 Window
对象也作为 JavaScript 的全局对象,因此对命名属性的变量声明或赋值将导致它们被新值替换。对于属性的变量声明不会创建替换现有属性的属性。
[Exposed =Window ,Global =Window ]interface Window {getter any (DOMString name );attribute DOMString name ; // ... };
以下 HTML 文档说明了如何覆盖 Window
对象上的命名属性,以及当声明与属性同名的变量时,属性的属性不会被替换:
<!DOCTYPE html> < title > 变量声明和 Window 上的赋值</ title > < iframe name = abc ></ iframe > <!-- 覆盖命名属性 --> < script > window. abc; // 评估为 iframe 的 Window 对象。 abc= 1 ; // 覆盖命名属性。 window. abc; // 评估为 1。 </ script > <!-- 保留 IDL 属性的属性 --> < script > Window. prototype. def= 2 ; // 在原型上放置属性。 window. hasOwnProperty( "length" ); // 评估为 true。 length; // 评估为 1。 def; // 评估为 2。 </ script > < script > var length; // 变量声明保留现有属性。 length; // 评估为 1。 var def; // 变量声明创建覆盖属性。 def; // 评估为 undefined。 </ script >
3.3.9. [NewObject]
如果 [NewObject
]
扩展属性 出现在 常规操作 或 静态操作 操作
上,则它表示在调用该操作时,必须始终返回对新创建对象的引用。
[NewObject
]
扩展属性只能用于其返回类型是接口类型或承诺类型的常规或静态操作。
例如,该扩展属性适用于 createElement()
操作,该操作属于 Document
接口,因为每次调用时都会返回一个新对象。[DOM]
[Exposed =Window ]interface Document :Node { [NewObject ]Element createElement (DOMString localName ); // ... };
3.3.10. [PutForwards]
如果 [PutForwards
]
扩展属性 出现在一个
只读 常规属性 声明中,并且该属性的类型是 接口类型,则表示赋值给该属性将具有特定行为。具体来说,赋值会被“转发”到当前引用的对象上的该扩展属性参数所指定的属性。
[PutForwards
]
扩展属性必须 带有一个标识符。假设:
-
A 是声明 [
PutForwards
] 扩展属性的 属性, -
I 是声明 A 的 接口,
-
J 是 A 被声明为的 接口类型,
-
N 是扩展属性的 标识符参数,
则在 J 上必须声明另一个 属性 B,其 标识符 是 N。对实现 I 的对象的属性 A 进行赋值将导致该值被赋予 A 所引用的对象的属性 B。
请注意,带有 [PutForwards
]
注释的 属性 可以被链接。也就是说,一个带有 [PutForwards
]
的属性可以引用另一个带有该扩展属性的属性。链式转发赋值中不得存在循环。如果在跟随转发赋值链时,某个 接口 上的特定属性被多次遇到,则存在循环。
带有 [PutForwards
]
的属性不得同时声明为带有 [LegacyLenientSetter
]
或 [Replaceable
]
扩展属性。
[PutForwards
]
扩展属性不得用于非只读的属性。
[PutForwards
]
扩展属性不得用于静态属性。
[PutForwards
]
扩展属性不得用于在命名空间上声明的属性。
有关如何实现 [PutForwards
]
,请参阅属性部分。
以下 IDL 片段
定义了名字和人的接口。[PutForwards
]
扩展属性用于 Person
接口的 name
属性,表明对该属性的赋值将导致对 Person
对象的 full
属性进行赋值:
[Exposed =Window ]interface Name {attribute DOMString full ;attribute DOMString family ;attribute DOMString given ; }; [Exposed =Window ]interface Person { [PutForwards =full ]readonly attribute Name name ;attribute unsigned short age ; };
在 JavaScript 绑定中,这将允许对 name
属性进行赋值:
var p= getPerson(); // 获取一个 Person 实例。 p. name= 'John Citizen' ; // 这条语句... p. name. full= 'John Citizen' ; // ...的行为与此相同。
3.3.11. [Replaceable]
如果 [Replaceable
]
扩展属性 出现在一个
只读 常规属性 中,则表示在 平台对象
上设置相应的属性将导致在该对象上创建一个具有相同名称的自有属性,该属性具有被赋予的值。这个属性将会遮蔽存在于 接口原型对象上的属性。
[Replaceable
]
扩展属性必须 不带参数。
带有 [Replaceable
]
的属性不得同时声明为带有 [LegacyLenientSetter
]
或 [PutForwards
]
扩展属性。
[Replaceable
]
扩展属性不得用于非只读的属性。
[Replaceable
]
扩展属性不得用于 静态属性。
[Replaceable
]
扩展属性不得用于声明在 命名空间中的属性。
有关 [Replaceable
]
的具体要求,请参阅 § 3.7.6 属性。
以下 IDL 片段定义了一个接口,该接口包含一个用于递增计数器的操作,以及一个用于公开计数器值的属性,该属性的初始值为 0:
[Exposed =Window ]interface Counter { [Replaceable ]readonly attribute unsigned long value ;undefined increment (); };
对实现 Counter
的平台对象的 value
属性进行赋值将遮蔽与属性对应的属性:
var counter= getCounter(); // 获取一个 Counter 实例。 counter. value; // 值为 0。 counter. hasOwnProperty( "value" ); // 结果为 false。 Object. getPrototypeOf( counter). hasOwnProperty( "value" ); // 结果为 true。 counter. increment(); counter. increment(); counter. value; // 结果为 2。 counter. value= 'a' ; // 用一个与 Counter::value 无关的值遮蔽该属性。 counter. hasOwnProperty( "value" ); // 结果为 true。 counter. increment(); counter. value; // 结果为 'a'。 delete counter. value; // 恢复原始属性。 counter. value; // 结果为 3。
3.3.12. [SameObject]
如果 [SameObject
]
扩展属性出现在只读属性上,则表示在获取给定对象上该属性的值时,必须始终返回相同的值。
[SameObject
]
扩展属性必须不带参数。
[SameObject
]
扩展属性只能用于类型为接口类型或 object
的只读属性。
例如,该扩展属性适用于 implementation
属性,它出现在 Document
接口中,因为对于给定的 Document
对象,总是返回相同的对象。 [DOM]
[Exposed =Window ]interface Document :Node { [SameObject ]readonly attribute DOMImplementation implementation ; // ... };
3.3.13. [SecureContext]
如果 [安全上下文
]
扩展属性 出现在
接口,部分接口,接口混合,部分接口混合,
回调接口,
命名空间,
部分命名空间,
接口成员,
接口混合成员,或
命名空间成员,
这表示该结构只在暴露于 安全上下文中。
[安全上下文
]
扩展属性不能用于其他构造中。
如果 [安全上下文
]
出现在 重载的操作上,
那么它必须出现在所有重载上。
注意:这是因为在 成员 上添加 [安全上下文
]
扩展属性,当它的包含定义也带有 [安全上下文
]
扩展属性
时,不会进一步限制该 成员 的暴露。
没有 [安全上下文
]
扩展属性 的 接口 不能 继承 另一个指定了 [安全上下文
]
的接口。
[安全上下文
]
不得在 有条件暴露 于 [跨源隔离
]
的构造中指定。
(因为每个 跨源隔离 的环境也是
安全上下文。)
以下 IDL 片段定义了一个接口,其中一个操作可从所有上下文执行,另外两个仅可从安全上下文执行。
[Exposed =Window ]interface ExampleFeature { // 此调用将在所有上下文中成功。Promise <Result >calculateNotSoSecretResult (); // 此操作不会暴露于非安全上下文。在这样的上下文中, // ExampleFeature.prototype 上将不会有 "calculateSecretResult" 属性。 [SecureContext ]Promise <Result >calculateSecretResult (); // 同样,此属性不会暴露于非安全上下文, // 在非安全上下文中,ExampleFeature.prototype 上将不会有 "secretBoolean" 属性。 [SecureContext ]readonly attribute boolean secretBoolean ; }; // HeartbeatSensor 不会暴露在非安全上下文中,其成员也不会。 // 在这种上下文中,Window 上将不会有 "HeartbeatSensor" 属性。 [Exposed =Window ,SecureContext ]interface HeartbeatSensor {Promise <float >getHeartbeatsPerMinute (); }; // 以下定义的接口混合成员永远不会暴露于非安全上下文, // 无论包含它们的接口是否暴露。也就是说,在非安全上下文中,ExampleFeature.prototype 上将不会有 "snap" 属性。 [SecureContext ]interface mixin Snapshotable {Promise <boolean >snap (); };ExampleFeature includes Snapshotable ; // 另一方面,当以下接口混合成员由不具有 [SecureContext] 扩展属性的宿主接口包含时,将暴露于非安全上下文。 // 也就是说,在非安全上下文中,ExampleFeature.prototype 上将有 "log" 属性。interface mixin Loggable {Promise <boolean >log (); };ExampleFeature includes Loggable ;
3.3.14. [Unscopable]
如果 [不可作用域
]
扩展属性 出现在
常规属性 或 常规操作
上,它表示具有该接口成员的接口的对象不会在任何以其为基础对象的对象环境记录中包含其属性名称。
其结果是在 with
语句中与属性名称匹配的裸标识符不会解析为该属性。 这是通过将属性名称包含在 接口原型对象 的 %Symbol.unscopables%
属性的值中实现的。
[不可作用域
]
扩展属性不得出现在 常规属性 或 常规操作 以外的任何地方。
[不可作用域
]
扩展属性不得用于在 命名空间 中声明的属性。
请参见 § 3.7.3 接口原型对象 以了解使用
[不可作用域
]
所涉及的具体要求。
例如,以下 IDL:
[Exposed =Window ]interface Thing {undefined f (); [Unscopable ]g (); };
f
属性可以在 with
语句中通过裸标识符引用,
但 g
属性则不能:
var thing= getThing(); // Thing 的实例 with ( thing) { f; // 返回一个 Function 对象。 g; // 抛出 ReferenceError。 }
3.4. 旧版扩展属性
本节定义了许多影响 JavaScript 绑定的扩展属性。与 § 3.3 扩展属性 中的不同, 这些属性仅存在于遗留 Web 平台功能中,只有在需要指定遗留 API 的行为时,才应在规范中使用。
认为有正当理由使用这些扩展属性的编辑强烈建议在继续之前通过 提交问题 来讨论。
3.4.1. [旧版工厂函数]
应使用 构造函数操作,而非此功能。
如果 [LegacyFactoryFunction
]
扩展属性
出现在 接口 上,
则表示 JavaScript 全局对象将具有一个指定名称的属性,其值是一个函数,该函数可创建实现该接口的对象。
可以在给定接口上出现多个 [LegacyFactoryFunction
]
扩展属性。
[LegacyFactoryFunction
]
扩展属性必须 带有命名参数列表。
在“LegacyFactoryFunction
]
的
标识符。
对于接口上的每个 [LegacyFactoryFunction
]
扩展属性,可以通过将指定的参数传递给上述属性值的 构造函数 来构造一个实现该接口的对象。
用于遗留工厂函数的 标识符 不得与其他接口上的 [LegacyFactoryFunction
]
扩展属性使用的标识符相同,
也不得与 标识符 相同,
还不得与具有 接口对象 的接口的
标识符 相同,且不得是 保留标识符 之一。
[LegacyFactoryFunction
]
和 [Global
]
扩展属性 不得在同一
接口 上指定。
关于遗留工厂函数的实现详情,请参阅 § 3.7.2 遗留工厂函数。
以下 IDL 定义了一个使用
[LegacyFactoryFunction
]
扩展属性的接口。
[Exposed =Window ,LegacyFactoryFunction =Audio (DOMString src )]interface HTMLAudioElement :HTMLMediaElement { // ... };
支持该接口的 JavaScript 实现将允许使用 Audio
函数构造 HTMLAudioElement
对象。
typeof Audio; // 结果为 'function'。 var a2= new Audio( 'a.flac' ); // 使用单参数构造函数创建 HTMLAudioElement。
作为额外的遗留怪癖,这些工厂函数将具有一个 prototype
属性,其值等于原始接口的 prototype
:
console. assert( Audio. prototype=== HTMLAudioElement. prototype);
3.4.2. [旧版宽松设置器]
如果 [LegacyLenientSetter
]
扩展属性
出现在 只读 常规属性 上,
则表示该属性的访问器属性将生成一个空操作 setter。这导致在严格模式下对该属性的错误赋值将被忽略,而不是抛出异常。
观察到某些页面的作者试图通过赋值属性来填充一个 IDL 属性,
但即使属性存在,也可能会意外这样做。在严格模式下,这将导致抛出异常,可能会破坏页面。没有
[LegacyLenientSetter
]
的话,这可能会阻止浏览器发布该功能。
[LegacyLenientSetter
]
扩展属性必须 不带任何参数。
它不得用于除 只读
常规属性
之外的任何事物上。
具有 [LegacyLenientSetter
]
扩展属性的属性不得同时使用 [PutForwards
]
或 [Replaceable
]
扩展属性。
[LegacyLenientSetter
]
扩展属性不得用于在 命名空间 中声明的属性。
请参见 属性 部分,了解如何实现
[LegacyLenientSetter
]。
以下 IDL 片段定义了一个使用
[LegacyLenientSetter
]
扩展属性的接口。
[Exposed =Window ]interface Example { [LegacyLenientSetter ]readonly attribute DOMString x ;readonly attribute DOMString y ; };
支持此接口的 JavaScript 实现将具有一个对应于 x 的访问器属性 setter, 它允许在严格模式下忽略任何赋值。
"use strict" ; var example= getExample(); // 获取 Example 的实例。 // 没问题;虽然我们处于严格模式,但有一个空操作的 setter。 example. x= 1 ; // 抛出 TypeError,因为我们处于严格模式,且没有 setter。 example. y= 1 ;
3.4.3. [旧版宽松this]
如果 [LegacyLenientThis
]
扩展属性
出现在 常规属性 上,
则表示在属性的 getter 或 setter 调用中,如果
[LegacyLenientThis
]
扩展属性必须 不带任何参数。
它不能用于 静态属性 上。
[LegacyLenientThis
]
扩展属性不得用于在 命名空间 中声明的属性。
请参阅 属性 部分,了解如何实现
[LegacyLenientThis
]。
以下 IDL 片段定义了一个使用
[LegacyLenientThis
]
扩展属性的接口。
[Exposed =Window ]interface Example { [LegacyLenientThis ]attribute DOMString x ;attribute DOMString y ; };
支持此接口的 JavaScript 实现将允许使用 Example
对象以外的对象调用 x 的 getter 和 setter。
var example= getExample(); // 获取 Example 的实例。 var obj= { }; // 正常。 example. x; // 被忽略,因为 this 值不是 Example 对象,且使用了 [LegacyLenientThis]。 Object. getOwnPropertyDescriptor( Example. prototype, "x" ). get. call( obj); // 同样被忽略,因为 Example.prototype 不是 Example 对象,且使用了 [LegacyLenientThis]。 Example. prototype. x; // 抛出 TypeError,因为 Example.prototype 不是 Example 对象。 Example. prototype. y;
3.4.4. [LegacyNamespace]
与其使用此功能,不如使用命名约定为一组接口的接口名称添加特定前缀,作为标识符的一部分,省略中间的点。
如果 [遗留命名空间
]
扩展属性
出现在 接口 上,它表示该接口的
接口对象
不会作为全局对象的属性创建,
而是作为由扩展属性参数标识的 命名空间 的属性创建。
[遗留命名空间
]
扩展属性必须 带有标识符。
该标识符必须是 标识符,并且是 命名空间 定义的标识符。
[遗留命名空间
]
和 [LegacyNoInterfaceObject
]
扩展属性不得在同一接口上指定。
有关接口如何在命名空间上暴露的详细信息,请参见 § 3.13.1 命名空间对象。
遗留命名空间
]
定义在其中的 接口。
namespace Foo { }; [LegacyNamespace =Foo ]interface Bar {constructor (); };
在 JavaScript 实现中,构造函数 Bar 可以这样访问:
var instance= new Foo. Bar();
3.4.5. [旧版无接口对象]
如果 [LegacyNoInterfaceObject
]
扩展属性 出现在
接口 上,
则表示该接口在 JavaScript 绑定中不会有 接口对象。
[LegacyNoInterfaceObject
]
扩展属性必须 不带任何参数。
[LegacyNoInterfaceObject
]
扩展属性不能出现在定义了任何 构造函数 或 静态操作 的接口上。
没有指定 [LegacyNoInterfaceObject
]
扩展属性的接口不能继承指定了 [LegacyNoInterfaceObject
]
扩展属性的接口。
有关使用 [LegacyNoInterfaceObject
]
的具体要求,请参阅 § 3.7 接口。
以下 IDL 片段 定义了两个接口, 其中一个接口对象暴露在 JavaScript 全局对象上,而另一个则没有:
[Exposed =Window ]interface Storage {undefined addEntry (unsigned long key ,any value ); }; [Exposed =Window ,LegacyNoInterfaceObject ]interface Query {any lookupEntry (unsigned long key ); };
上述 IDL 的 JavaScript 实现将允许对 Storage
的原型进行操作,但不允许对 Query
进行操作。
typeof Storage; // 结果为 "object" // 为 Storage.addEntry 添加一些跟踪 alert() 调用。 var fn= Storage. prototype. addEntry; Storage. prototype. addEntry= function ( key, value) { alert( '调用 addEntry()' ); return fn. call( this , key, value); }; typeof Query; // 结果为 "undefined" var fn= Query. prototype. lookupEntry; // 异常,Query 未定义
3.4.6. [旧版Null转为空字符串]
如果 [LegacyNullToEmptyString
]
扩展属性 出现在
DOMString
或 USVString
类型上,
它将创建一个新的 IDL 类型,使得当 JavaScript 中的 null
",而使用此扩展属性后将转换为空字符串。
[LegacyNullToEmptyString
]
扩展属性不得 关联 非
DOMString
或 USVString
的类型。
注意:这意味着即使 DOMString?
也不能使用
[LegacyNullToEmptyString
],
因为
有关使用 [LegacyNullToEmptyString
]
的具体要求,请参阅 § 3.2.10 DOMString。
[Exposed =Window ]interface Dog {attribute DOMString name ;attribute [LegacyNullToEmptyString ]DOMString owner ;boolean isMemberOfBreed ([LegacyNullToEmptyString ]DOMString breedName ); };
实现 Dog
接口的 JavaScript 实现将把分配给 owner
属性或传递给
isMemberOfBreed
函数的 null
":
var d= getDog(); // 假设 d 是实现 Dog 接口的平台对象。 d. name= null ; // 这会将字符串 "null" 分配给 .name 属性。 d. owner= null ; // 这会将空字符串 "" 分配给 .owner 属性。 d. isMemberOfBreed( null ); // 这会将空字符串 "" 传递给 isMemberOfBreed 函数。
3.4.7. [旧版覆盖内置]
如果 [LegacyOverrideBuiltIns
]
扩展属性 出现在
接口 上,
则表示对于实现该接口的 遗留平台对象,对象的所有
支持的属性名称
将显示在对象上,而不管该对象或其原型链上是否存在其他属性。这意味着命名属性将始终覆盖对象上原本存在的任何属性。
这与通常的行为相反,通常只有当对象本身或其原型链上没有相同名称的属性时,命名属性才会暴露。
[LegacyOverrideBuiltIns
]
扩展属性必须 不带任何参数,
并且不得出现在未定义 命名属性 getter 的接口上,也不得与 [Global
]
扩展属性一起声明。
如果扩展属性指定在 部分接口
定义上,那么该部分接口定义必须是定义了 命名属性 getter 的接口定义的一部分。
如果 [LegacyOverrideBuiltIns
]
扩展属性指定在 部分接口
定义上,则该扩展属性将被视为出现在整个
接口 上。
有关 [LegacyOverrideBuiltIns
]
使用的具体要求,请参阅 § 3.9 遗留平台对象 和
§ 3.9.3 [[DefineOwnProperty]]。
以下 IDL 片段 定义了两个 接口, 一个具有 命名属性 getter, 另一个没有。
[Exposed =Window ]interface StringMap {readonly attribute unsigned long length ;getter DOMString lookup (DOMString key ); }; [Exposed =Window ,LegacyOverrideBuiltIns ]interface StringMap2 {readonly attribute unsigned long length ;getter DOMString lookup (DOMString key ); };
在这两个接口的 JavaScript 实现中,获取实现这些接口的对象的某些属性将会得到不同的值:
// 获取 StringMap 的实例。假设它的支持属性名称为 "abc"、"length" 和 "toString"。 var map1= getStringMap(); // 这将调用命名属性 getter。 map1. abc; // 这将获取与 length 属性对应的对象上的 "length" 属性。 map1. length; // 这将从对象的原型链中获取 "toString" 属性。 map1. toString; // 获取 StringMap2 的实例。假设它也有 "abc"、"length" 和 "toString" 作为支持属性名称。 var map2= getStringMap2(); // 这将调用命名属性 getter。 map2. abc; // 这也将调用命名属性 getter,尽管对象上的 "length" 属性对应于 length 属性。 map2. length; // 这同样将调用命名属性 getter,尽管 "toString" 是 map2 原型链中的一个属性。 map2. toString;
3.4.8. [旧版视非对象为空值]
如果 [LegacyTreatNonObjectAsNull
]
扩展属性 出现在
回调函数上,
则表示分配给类型为 可空
的 回调函数 的
属性 的任何值将被更松散地转换:
如果该值不是对象,则将其转换为 null,并且如果该值不是 可调用,则将其转换为一个在调用时
不执行任何操作的 回调函数。
有关使用 [LegacyTreatNonObjectAsNull
]
的具体要求,请参阅 § 3.2.20 可空类型 — T?、§ 3.2.19
回调函数类型
和 § 3.12 调用回调函数。
以下 IDL 片段 定义了一个接口,
其中一个属性的类型是带有 [LegacyTreatNonObjectAsNull
]
注释的 回调函数,
另一个属性的类型是没有 扩展属性
的 回调函数:
callback OccurrenceHandler =undefined (DOMString details ); [LegacyTreatNonObjectAsNull ]callback ErrorHandler =undefined (DOMString details ); [Exposed =Window ]interface Manager {attribute OccurrenceHandler ?handler1 ;attribute ErrorHandler ?handler2 ; };
在 JavaScript 实现中,将不是对象的值(例如 Number 值)或不是 可调用 的值分配给 handler1 和 handler2 时,将会产生不同的行为:
var manager= getManager(); // 获取 Manager 的实例。 manager. handler1= function () { }; manager. handler1; // 结果为该函数。 try { manager. handler1= 123 ; // 抛出 TypeError。 } catch ( e) { } try { manager. handler1= {}; // 抛出 TypeError。 } catch ( e) { } manager. handler2= function () { }; manager. handler2; // 结果为该函数。 manager. handler2= 123 ; manager. handler2; // 结果为 null。 manager. handler2= {}; manager. handler2; // 结果为该对象。
3.4.9. [LegacyUnenumerableNamedProperties]
如果 [LegacyUnenumerableNamedProperties
]
扩展属性 出现在
支持命名属性的接口 上,
则表示该接口的所有命名属性都是不可枚举的。
[LegacyUnenumerableNamedProperties
]
扩展属性必须 不带任何参数,
且不得出现在没有定义 命名属性 getter
的接口上。
如果 [LegacyUnenumerableNamedProperties
]
扩展属性在接口上指定,则它适用于所有派生接口,并且不得在它们中的任何一个上指定。
有关使用 [LegacyUnenumerableNamedProperties
]
的具体要求,请参阅 § 3.9.1 [[GetOwnProperty]]。
3.4.10. [旧版不可伪造]
如果 [LegacyUnforgeable
]
扩展属性 出现在
常规属性 或 非
静态
操作上,
则表示该属性或操作将以 JavaScript 属性的形式反映,
其行为不可被修改,并且在对象上执行属性查找时将始终返回该属性的值。
特别是,该属性将是不可配置的,并且作为对象本身的自有属性存在,而不是在其原型链上。
如果一个属性或操作在给定接口 A 上被称为
不可伪造,
则该属性或操作在 A 上被声明,并且带有 [LegacyUnforgeable
]
扩展属性。
[LegacyUnforgeable
]
扩展属性必须 不带任何参数。
[LegacyUnforgeable
]
扩展属性不得出现在 常规属性 或 非
静态
操作 之外的任何地方。
如果它出现在 操作 上,
则它必须出现在该接口上具有相同 标识符
的所有操作上。
[LegacyUnforgeable
]
扩展属性不得用于声明在 命名空间上的属性。
如果一个属性或操作 X 是在接口 A 上的 不可伪造属性或操作, 且 A 是另一个接口 B 的 继承接口之一, 则 B 不得具有与 X 具有相同 标识符 的 常规属性 或 非 静态 操作。
例如,以下是不允许的:
[Exposed =Window ]interface A1 { [LegacyUnforgeable ]readonly attribute DOMString x ; }; [Exposed =Window ]interface B1 :A1 {undefined x (); // 无效;会被 A1 的 x 遮蔽。 }; [Exposed =Window ]interface B2 :A1 { };B2 includes M1 ;interface mixin M1 {undefined x (); // 无效;B2 的 x 会被 A1 的 x 遮蔽。 };
请参阅 § 3.7.6 属性,§ 3.7.7 操作,
§ 3.8 实现接口的平台对象,§ 3.9 旧平台对象 和
§ 3.9.3 [[DefineOwnProperty]]
以了解 [LegacyUnforgeable
]
的具体使用要求。
以下 IDL 片段
定义了一个包含两个 属性的接口,
其中一个属性被标记为 [LegacyUnforgeable
]:
[Exposed =Window ]interface System { [LegacyUnforgeable ]readonly attribute DOMString username ;readonly attribute long long loginTime ; };
在接口的 JavaScript 实现中,username 属性将作为对象本身的不可配置属性暴露:
var system= getSystem(); // 获取 System 的实例。 system. hasOwnProperty( "username" ); // 结果为 true。 system. hasOwnProperty( "loginTime" ); // 结果为 false。 System. prototype. hasOwnProperty( "username" ); // 结果为 false。 System. prototype. hasOwnProperty( "loginTime" ); // 结果为 true。 try { // 此调用将失败,因为属性不可配置。 Object. defineProperty( system, "username" , { value: "administrator" }); } catch ( e) { } // 由于 System.prototype.loginTime 是可配置的,因此 defineProperty 调用将成功。 var forgedLoginTime= 5 ; Object. defineProperty( System. prototype, "loginTime" , { value: forgedLoginTime}); system. loginTime; // 因此现在评估为 forgedLoginTime。
3.4.11. [LegacyWindowAlias]
如果 [LegacyWindowAlias
]
扩展属性出现在一个接口上,
它表示 Window
接口将为扩展属性中提及的每个标识符拥有一个属性,
其值为该接口的接口对象。
[LegacyWindowAlias
]
扩展属性必须要么 采用标识符,
要么 采用标识符列表。
在 “LegacyWindowAlias
]
的 标识符。
[LegacyWindowAlias
]
的每个 标识符 不得与此接口或其他接口上的任何 [LegacyWindowAlias
]
扩展属性使用的标识符相同,
不得与此接口或其他接口上的 [LegacyFactoryFunction
]
扩展属性使用的 标识符 相同,
也不得与具有 接口对象 的接口的
标识符 相同,
并且不得是 保留标识符 之一。
[LegacyWindowAlias
]
和 [LegacyNoInterfaceObject
]
扩展属性不得在同一接口上指定。
[LegacyWindowAlias
]
和 [LegacyNamespace
]
扩展属性不得在同一接口上指定。
[LegacyWindowAlias
]
扩展属性不得在接口上指定,如果该接口的暴露集中不包含 Window
接口。
一个接口不得有多个 [LegacyWindowAlias
]
扩展属性指定。
请参阅 § 3.7 接口 以了解如何实现旧窗口别名。
以下 IDL 定义了一个使用 [LegacyWindowAlias
]
扩展属性的接口。
[Exposed =Window ,LegacyWindowAlias =WebKitCSSMatrix ]interface DOMMatrix :DOMMatrixReadOnly { // ... };
支持此接口的 JavaScript 实现将在 Window
对象上暴露两个具有相同值和相同特性的属性;
一个用于正常暴露 接口对象,
另一个用于以旧名称暴露它。
WebKitCSSMatrix=== DOMMatrix; // 结果为 true。 var m= new WebKitCSSMatrix(); // 创建一个新对象,实现 DOMMatrix。 m. constructor === DOMMatrix; // 结果为 true。 m. constructor === WebKitCSSMatrix; // 结果为 true。 {}. toString. call( m); // 结果为 '[object DOMMatrix]'。
3.5. 安全性
下面章节中的某些算法被定义为对给定对象执行安全检查。 此检查用于确定是否应允许给定的操作调用或属性访问。 安全检查接受以下三个输入:
-
正在执行操作调用或属性访问的 平台对象,
-
操作或属性的 标识符,
-
函数对象的类型 – "
method
"(当它对应于 IDL 操作时),或 "getter
" 或 "setter
"(当它对应于 IDL 属性的 getter 或 setter 函数时)。
注意: HTML 标准定义了如何执行安全检查。 [HTML]
3.6. 重载解析算法
为了定义如何解析函数调用,定义了 重载解析算法。 它的输入是一个 有效重载集,S, 和一个 JavaScript 值的列表,args。其输出是一对, 包含 操作 或 扩展属性 中 S 条目的一个和 IDL 值列表或特殊值 "missing"。该算法的行为如下:
-
令 maxarg 为 S 中条目中最长的类型列表的长度。
-
令 n 为 args 的 大小。
-
将 argcount 初始化为 min(maxarg, n)。
-
从 S 中删除其类型列表长度不为 argcount 的所有条目。
-
将 d 初始化为 −1。
-
将 method 初始化为
undefined 。 -
如果 S 中有多个条目,则将 d 设置为 区分参数索引, 适用于 S 中的条目。
-
将 values 初始化为空列表,其中每个条目将是一个 IDL 值或特殊值 “missing”。
-
将 i 初始化为 0。
-
当 i 小于 d 时:
-
如果 i 等于 d,则:
-
令 V 为 args[i]。
注意:这是用于决定选择哪个重载的参数。
-
如果 V 是
undefined 且 S 中有一个条目的可选性值 列表中索引 i 处为 “optional”,则从 S 中删除所有其他条目。 -
否则:如果 V 是
null 或undefined 且 S 中有一个条目在其类型列表的索引 i 处具有以下类型之一,则从 S 中删除所有其他条目。
-
否则:如果 V 是一个平台对象 且 S 中有一个条目在其类型列表的 索引 i 处具有以下类型之一,
-
上述任一类型的 可空版本
则从 S 中删除所有其他条目。
-
否则:如果 V 是一个对象,V 有一个 [[ArrayBufferData]] 内部插槽,并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
-
上述任何类型的 可空版本
然后从 S 中删除所有其他条目。
-
否则:如果 V 是一个对象,V 有一个 [[DataView]] 内部插槽,并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
然后从 S 中删除所有其他条目。
-
否则:如果 V 是一个对象,V 有一个 [[TypedArrayName]] 内部插槽,并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
-
上述任何类型的 可空版本
然后从 S 中删除所有其他条目。
-
否则:如果 IsCallable(V) 为 true,并且在 S 中有一个条目在 i 位置具有以下类型之一,
然后从 S 中删除所有其他条目。
-
否则:如果 V 是一个对象并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
并且以下情况并非全部为真,
-
V 有一个 [[StringData]] 内部插槽
-
S 的类型列表的第 i 个位置具有以下类型之一,
并且在执行以下步骤后,
-
令 method 为 ? GetMethod(V,
%Symbol.asyncIterator%
)。 -
如果 method 是
undefined ,则将 method 设置为 ? GetMethod(V,%Symbol.iterator%
)。
如果 method 不是
undefined ,则从 S 中移除所有其他条目。 -
-
否则:如果 V 是一个对象并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
并且在执行以下步骤后,
-
令 method 为 ? GetMethod(V,
%Symbol.iterator%
)。
如果 method 不是
undefined ,则从 S 中移除所有其他条目。 -
-
否则:如果 V 是一个对象并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
则从 S 中移除所有其他条目。
-
否则:如果 V 是一个布尔值并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
则从 S 中移除所有其他条目。
-
否则:如果 V 是一个数字并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
则从 S 中移除所有其他条目。
-
否则:如果 V 是一个 BigInt 并且 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
则从 S 中移除所有其他条目。
-
否则:如果 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
则从 S 中移除所有其他条目。
-
否则:如果 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
则从 S 中移除所有其他条目。
-
否则:如果 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
则从 S 中移除所有其他条目。
-
否则:如果 S 中有一个条目,其类型列表的第 i 个位置具有以下类型之一,
则从 S 中移除所有其他条目。
-
否则:如果 S 中有一个条目,其类型列表的第 i 个位置是
any
,则从 S 中移除所有其他条目。
-
-
如果 i = d 且 method 不是
undefined ,则 -
当 i < argcount 时:
-
当 i 小于 callable 声明的参数数量时:
-
如果 callable 的索引 i 处的参数声明了 默认值,则将该默认值追加到 values。
-
否则,如果 callable 的索引 i 处的参数不是可变参数,则将特殊值 “missing” 追加到 values。
-
将 i 设置为 i + 1。
-
-
返回 <callable, values>。
重载解析算法同时执行了识别被调用的重载操作、构造函数等,并将 JavaScript 参数值转换为其相应的 IDL 值。非正式地说,它的工作过程如下。
首先,通过考虑传递给函数的 JavaScript 参数的数量来选择有效的重载:
-
如果传递的参数数量超过了最长的重载参数列表,那么这些参数将被忽略。
-
忽略这些尾随参数后,只考虑可以接受这个确切数量参数的重载。如果没有这样的重载,则抛出
TypeError
。
一旦我们有了一组具有正确参数数量的可能重载, JavaScript 值就会从左到右进行转换。 重载限制的性质意味着,如果此时我们有多个可能的重载, 那么参数列表中将会有一个位置用于区分我们将最终选择哪个重载; 这就是区分参数索引。
我们首先转换区分参数左侧的参数。
(要求是,区分参数索引左侧的参数必须与相同索引处其他重载中的类型相同。)
然后我们检查在区分参数索引处传入的 JavaScript 值的类型,
以确定它可以对应于哪个 IDL 类型。
这使我们能够选择将最终调用的重载。
如果传入的值是 TypeError
。
通常,对区分参数索引处的值的检查没有任何副作用,
重载解析算法中唯一的副作用是转换 JavaScript 值到 IDL 值的结果。
(当其中一个重载在区分参数索引处具有异步可迭代类型、序列类型或冻结数组类型时,存在一个例外。
在这种情况下,我们尝试获取 %Symbol.asyncIterator%
/ %Symbol.iterator%
属性以确定适当的重载,并在继续下一步之前单独执行区分参数的转换。)
此时,我们已经确定了要使用的重载。我们现在转换剩余的参数, 从区分参数开始,再次忽略由于在最后一个可能的参数之后传递而被忽略的任何其他参数。
当将可选参数的 JavaScript 值转换为其等效的 IDL 值时,
然而,对应于最后一个可变参数的可选参数不会将
3.7. 接口
对于在给定领域中暴露的、且未使用 [LegacyNoInterfaceObject
]
或 [LegacyNamespace
]
扩展属性声明的每个接口,
在领域的全局对象上存在一个对应的属性。
该属性的名称是接口的标识符,
其值是一个称为接口对象的对象。
接口对象的特性在 § 3.7.1 接口对象中描述。
如果在暴露的接口上指定了 [LegacyWindowAlias
]
扩展属性,
那么对于 [LegacyWindowAlias
]
的
标识符中的每个标识符,在 Window
全局对象上都存在一个对应的属性。
该属性的名称是给定的标识符,
其值是对该接口的接口对象的引用。
此外,对于暴露的接口上的每个 [LegacyFactoryFunction
]
扩展属性,
JavaScript 全局对象上都存在一个对应的属性。
该属性的名称是 [LegacyFactoryFunction
]
的
标识符,
其值是一个称为旧版工厂函数的对象,
它允许创建实现该接口的对象。
旧版工厂函数的特性在 § 3.7.2 旧版工厂函数中描述。
要对接口 interface 执行 对象的实现检查,使用标识符 name 和类型 type 对 jsValue 进行检查:
该算法尚未在所有地方一致使用。
3.7.1. 接口对象
给定接口的接口对象是一个内置函数对象。 它具有与该接口上定义的常量和静态操作相对应的属性, 如 § 3.7.5 常量和 § 3.7.7 操作章节所述。
如果接口使用构造函数操作声明, 则可以将接口对象作为构造函数调用以创建实现该接口的对象。 将该接口作为函数调用将抛出异常。
未使用构造函数操作声明的接口的接口对象在作为函数和作为构造函数调用时都将抛出异常。
接口的接口对象具有一个关联对象,称为接口原型对象。 此对象具有与接口上定义的常规属性和常规操作相对应的属性, 并在 § 3.7.3 接口原型对象中有更详细的描述。
注意:由于接口对象是一个函数对象,因此当 typeof
操作符应用于接口对象时将返回 "function"。
接口可能具有覆盖的构造步骤,这可以更改接口对象在调用或构造时的行为。默认情况下,接口没有这样的步骤。
通常,通过定义构造函数操作及其行为来描述构造函数。覆盖的构造步骤仅用于更复杂的情况。编辑者希望使用此功能时,强烈建议在继续之前通过 提交问题进行讨论。
给定接口 I(其标识符为 id,位于领域 realm 中)的接口对象按如下方式创建:
-
令 steps 为 I 的被覆盖的构造函数步骤(如果存在),否则为以下步骤:
-
令 args 为传入的参数。
-
令 n 为 args 的大小。
-
令 id 为接口 I 的标识符。
-
令 <constructor, values> 为将 S 和 args 传递给重载解析算法的结果。
-
令 O 为 object,转换为 JavaScript 值。
-
断言:O 是一个实现 I 的对象。
-
断言:O.[[Realm]] 是 realm。
-
返回 O。
-
令 constructorProto 为 realm.[[Intrinsics]].[[
%Function.prototype%
]]。 -
如果 I 继承自某个其他接口 P, 则将 constructorProto 设置为 realm 中 P 的接口对象。
-
令 F 为 CreateBuiltinFunction(steps, « [[Unforgeables]] », realm, constructorProto)。
-
令 unforgeables 为 OrdinaryObjectCreate(
null )。 -
给定 realm,在 unforgeables 上定义 I 的不可伪造常规操作。
-
给定 realm,在 unforgeables 上定义 I 的不可伪造常规属性。
-
将 F.[[Unforgeables]] 设置为 unforgeables。
注意:此对象永远不会暴露给用户代码。它仅用于确保具有不可伪造成员的接口的所有实例对属性获取器、属性设置器和操作函数使用相同的 JavaScript 函数对象。
-
执行 SetFunctionName(F, id)。
-
令 length 为 0。
-
如果 I 使用构造函数操作声明,则
-
执行 SetFunctionLength(F, length)。
-
执行 ! DefinePropertyOrThrow(F, "
prototype
", PropertyDescriptor{[[Value]]: proto, [[Writable]]:false , [[Enumerable]]:false , [[Configurable]]:false })。 -
返回 F。
3.7.2. 旧版工厂函数
由于一个或多个 [LegacyFactoryFunction
]
扩展属性 而存在的
遗留工厂函数 是一个 内置函数对象。 它允许构造实现该接口的对象,其中 [LegacyFactoryFunction
]
扩展属性出现在接口上。
给定接口 I 在 领域 realm 中,其标识符为 id 的旧版工厂函数按如下方式创建:
-
令 steps 为以下步骤:
-
令 args 为传入的参数。
-
令 n 为 args 的大小。
-
令 <constructor, values> 为将 S 和 args 传递给重载解析算法的结果。
-
令 O 为 object,转换为 JavaScript 值。
-
断言:O 是一个实现 I 的对象。
-
断言:O.[[Realm]] 是 realm。
-
返回 O。
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, id)。
-
令 length 为 S 中条目的最短参数列表的长度。
-
执行 SetFunctionLength(F, length)。
-
执行 ! DefinePropertyOrThrow(F, "
prototype
", PropertyDescriptor{[[Value]]: proto, [[Writable]]:false , [[Enumerable]]:false , [[Configurable]]:false })。 -
返回 F。
3.7.3. 接口原型对象
对于定义的每个接口,都将存在一个接口原型对象,
无论该接口是否使用 [LegacyNoInterfaceObject
]
扩展属性声明。
给定接口 interface 和领域 realm 的接口原型对象按如下方式创建:
-
令 proto 为 null。
-
如果 interface 使用 [
Global
] 扩展属性声明, 并且 interface 支持命名属性, 则将 proto 设置为为 interface 和 realm 创建命名属性对象的结果。 -
否则,如果 interface 声明为继承自另一个接口, 则将 proto 设置为该继承接口在 realm 中的接口原型对象。
-
否则,如果 interface 是
DOMException
接口, 则将 proto 设置为 realm.[[Intrinsics]].[[%Error.prototype%
]]。 -
否则,将 proto 设置为 realm.[[Intrinsics]].[[
%Object.prototype%
]]。 -
断言:proto 是一个对象。
-
令 interfaceProtoObj 为 null。
-
如果 realm 的全局原型链是否可变为 true,则:
-
将 interfaceProtoObj 设置为 OrdinaryObjectCreate(proto)。
-
-
否则,如果 interface 使用 [
Global
] 扩展属性声明,或者 interface 位于使用 [Global
] 扩展属性声明的接口的继承接口集合中,则:-
将 interfaceProtoObj 设置为 MakeBasicObject(« [[Prototype]], [[Extensible]] »)。
-
将 interfaceProtoObj.[[Prototype]] 设置为 proto。
-
将 interfaceProtoObj 特有的不可变原型奇异对象的内部方法设置为 ECMA-262 不可变原型奇异对象中指定的定义。
-
-
否则,将 interfaceProtoObj 设置为 OrdinaryObjectCreate(proto)。
-
如果 interface 具有任何使用 [
Unscopable
] 扩展属性声明的成员, 则:-
令 unscopableObject 为 OrdinaryObjectCreate(
null )。 -
对于 interface 中每个使用 [
Unscopable
] 扩展属性声明的暴露的成员 member:-
令 id 为 member 的标识符。
-
执行 ! CreateDataPropertyOrThrow(unscopableObject, id,
true )。
-
-
令 desc 为 PropertyDescriptor{[[Value]]: unscopableObject, [[Writable]]:
false , [[Enumerable]]:false , [[Configurable]]:true }。 -
执行 ! DefinePropertyOrThrow(interfaceProtoObj,
%Symbol.unscopables%
, desc)。
-
-
如果 interface 未使用 [
Global
] 扩展属性声明,则:-
给定 realm,在 interfaceProtoObj 上定义 interface 的常规属性。
-
给定 realm,在 interfaceProtoObj 上定义 interface 的常规操作。
-
给定 realm,在 interfaceProtoObj 上定义 interface 的迭代方法。
-
给定 realm,在 interfaceProtoObj 上定义 interface 的异步迭代方法。
-
-
给定 realm,在 interfaceProtoObj 上定义 interface 的常量。
-
如果 interface 上未指定 [
LegacyNoInterfaceObject
] 扩展属性,则:-
令 constructor 为 realm 中 interface 的接口对象。
-
令 desc 为 PropertyDescriptor{[[Writable]]:
true , [[Enumerable]]:false , [[Configurable]]:true , [[Value]]: constructor}。 -
执行 ! DefinePropertyOrThrow(interfaceProtoObj, "
constructor
", desc)。
-
-
返回 interfaceProtoObj。
此外,接口原型对象从以下位置声明性地获取属性:
改为命令式地定义这些属性。
使用 [LegacyNoInterfaceObject
]
扩展属性定义的接口的接口原型对象将是可访问的。
例如,对于以下 IDL:
[Exposed =Window ,LegacyNoInterfaceObject ]interface Foo { };partial interface Window {attribute Foo foo ; };
无法通过接口对象访问接口原型对象(因为它不存在于 window.Foo
)。
然而,Foo
的实例可以通过调用其 [[GetPrototypeOf]] 内部方法来暴露接口原型对象——
在此示例中为 Object.getPrototypeOf(window.foo)
。
3.7.4. 命名属性对象
对于每个使用 [Global
]
扩展属性声明且支持命名属性的接口,
都将存在一个称为该接口的命名属性对象的对象,命名属性在该对象上公开。
-
令 proto 为 null。
-
否则,将 proto 设置为 realm.[[Intrinsics]].[[
%Object.prototype%
]]。 -
令 obj 为 MakeBasicObject(« [[Prototype]], [[Extensible]] »)。
-
按照 § 3.7.4.1 [[GetOwnProperty]] 中的规定设置 obj.[[GetOwnProperty]]。
-
按照 § 3.7.4.2 [[DefineOwnProperty]] 中的规定设置 obj.[[DefineOwnProperty]]。
-
按照 § 3.7.4.3 [[Delete]] 中的规定设置 obj.[[Delete]]。
-
按照 § 3.7.4.4 [[SetPrototypeOf]] 中的规定设置 obj.[[SetPrototypeOf]]。
-
按照 § 3.7.4.5 [[PreventExtensions]] 中的规定设置 obj.[[PreventExtensions]]。
-
将 obj.[[Prototype]] 设置为 proto。
-
返回 obj。
注意:命名属性对象的 [[OwnPropertyKeys]] 内部方法 继续使用 OrdinaryOwnPropertyKeys, 这与旧版平台对象的对应方法不同。 由于命名属性不是“真正的”自有属性, 因此该内部方法不会返回它们。
命名属性对象的类字符串是接口的标识符和字符串 "Properties
" 的串联。
3.7.4.1. [[GetOwnProperty]]
当调用命名属性对象O的[[GetOwnProperty]]内部方法,并传入属性键P时,执行以下步骤:
-
令A为O的接口。
-
令object为O.[[Realm]]的全局对象。
-
断言:object 实现了A。
-
如果使用属性名称P和对象object运行命名属性可见性算法的结果为true,则执行以下操作:
-
令operation为用于声明命名属性getter的操作。
-
令value为一个未初始化的变量。
-
否则,operation是具有标识符的定义。将value设置为根据operation的描述,并将P作为唯一参数值执行步骤的结果。
-
令desc为一个新创建的属性描述符,且不包含任何字段。
-
将desc.[[Value]]设置为转换value为JavaScript值的结果。
-
如果A 实现了具有[
LegacyUnenumerableNamedProperties
] 扩展属性的接口,则将desc.[[Enumerable]]设置为false ,否则将其设置为true 。 -
将desc.[[Writable]]设置为
true ,将desc.[[Configurable]]设置为true 。 -
返回desc。
-
-
返回OrdinaryGetOwnProperty(O, P)。
3.7.4.2. [[DefineOwnProperty]]
当调用命名属性对象的[[DefineOwnProperty]]内部方法时,执行以下步骤:
-
返回
false 。
3.7.4.3. [[Delete]]
当调用命名属性对象的[[Delete]]内部方法时,执行以下步骤:
-
返回
false 。
3.7.4.4. [[SetPrototypeOf]]
当调用命名属性对象O的[[SetPrototypeOf]]内部方法,并传入JavaScript值V时,执行以下步骤:
-
如果O的关联领域的全局原型链可变性为true,返回? OrdinarySetPrototypeOf(O, V)。
-
返回? SetImmutablePrototype(O, V)。
3.7.4.5. [[PreventExtensions]]
当调用命名属性对象的[[PreventExtensions]]内部方法时,执行以下步骤:
-
返回
false 。
注意:这使得命名属性对象通过使[[PreventExtensions]]失败而保持可扩展性。
3.7.5. 常量
常量暴露在接口对象、旧版回调接口对象、接口原型对象上,以及当接口使用
[Global
] 扩展属性声明时,在实现该接口的单个对象上。
3.7.6. 属性
静态属性暴露在接口对象上。常规属性暴露在接口原型对象上,除非该属性是不可伪造的或接口是通过[Global
] 扩展属性声明的,这种情况下,它们暴露在实现该接口的每个对象上。
-
-
创建attr的属性getter,给定attr、定义和realm,并将结果赋值给getter。
-
创建attr的属性setter,给定attr、定义和realm,并将结果赋值给setter。
-
如果attr是不可伪造的,则将configurable设为
false ,否则设为true 。 -
将desc设为PropertyDescriptor{[[Get]]: getter, [[Set]]: setter, [[Enumerable]]:
true , [[Configurable]]: configurable}。 -
将id设为attr的标识符。
-
执行 ! DefinePropertyOrThrow(target, id, desc)。
-
如果attr的类型是带有类型参数T的可观察数组类型,则将target的可观察数组异类对象的后备设置为realm中创建的可观察数组异类对象的结果,给定T、attr的设置索引值算法和attr的删除索引值算法。
属性获取器按如下方式创建,给定一个属性 attribute、一个命名空间或接口 target,以及一个领域 realm:
-
令 steps 为以下系列步骤:
-
尝试运行以下步骤:
-
令 idlObject 为 null。
-
如果 target 是一个接口,并且 attribute 是一个常规属性:
-
令 jsValue 为
this 值(如果它不是null 或undefined ),否则为 realm 的全局对象。 (如果全局对象未实现 target 且未指定 [LegacyLenientThis
],这将在后续几个步骤中导致TypeError
。) -
如果 jsValue 是一个平台对象,则执行安全检查, 传递 jsValue、attribute 的标识符和 "getter"。
-
如果 jsValue 未实现 target,则:
-
如果 attribute 使用 [
LegacyLenientThis
] 扩展属性指定,则返回undefined 。
-
-
如果 attribute 的类型是可观察数组类型, 则返回 jsValue 针对 attribute 的支持的可观察数组奇异对象。
-
将 idlObject 设置为表示对 jsValue 引用的 IDL 接口类型值。
-
-
返回将 R 转换为 attribute 声明的类型的 JavaScript 值的结果。
-
然后,如果抛出了异常 E:
-
如果 attribute 的类型是promise 类型,则返回 ! Call(
%Promise.reject%
,%Promise%
, «E»)。 -
否则,结束这些步骤并允许异常传播。
-
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
令 name 为在 attribute 的标识符前加上字符串 "
get
" 的结果。 -
执行 SetFunctionName(F, name)。
-
执行 SetFunctionLength(F, 0)。
-
返回 F。
属性设置器按如下方式创建,给定一个属性 attribute、一个命名空间或接口 target,以及一个领域 realm:
-
如果 target 是一个命名空间:
-
断言:attribute 是只读的。
-
返回
undefined 。
-
-
如果 attribute 是只读的并且没有 [
LegacyLenientSetter
]、 [PutForwards
] 或 [Replaceable
] 扩展属性,则返回undefined ;不存在属性设置器函数。 -
断言:attribute 的类型不是promise 类型。
-
令 steps 为以下系列步骤:
-
令 V 为传递的第一个参数的值。
-
令 id 为 attribute 的标识符。
-
令 idlObject 为 null。
-
如果 attribute 是一个常规属性:
-
令 jsValue 为
this 值(如果它不是null 或undefined ),否则为 realm 的全局对象。 (如果全局对象未实现 target 且未指定 [LegacyLenientThis
],这将在后续几个步骤中导致TypeError
。) -
如果 jsValue 实现了 target,则令 validThis 为 true,否则为 false。
-
如果 validThis 为 false 且 attribute 未使用 [
LegacyLenientThis
] 扩展属性指定,则抛出一个TypeError
。 -
如果 attribute 使用 [
Replaceable
] 扩展属性声明,则:-
执行 ? CreateDataPropertyOrThrow(jsValue, id, V)。
-
返回
undefined 。
-
-
如果 validThis 为 false,则返回
undefined 。 -
如果 attribute 使用 [
LegacyLenientSetter
] 扩展属性声明,则 返回undefined 。 -
如果 attribute 使用 [
PutForwards
] 扩展属性声明,则: -
将 idlObject 设置为表示对 jsValue 引用的 IDL 接口类型值。
-
如果 attribute 的类型是类型参数为 T 的可观察数组类型:
-
令 newValues 为将 V 转换为类型为 sequence<T> 的 IDL 值的结果。
-
令 oa 为 idlObject 的 attribute 的支持的可观察数组奇异对象。
-
设置 oa.[[ProxyHandler]] 的长度为 0。
-
令 i 为 0。
-
当 i < newValues 的大小时:
-
给定 newValues[i] 和 i,执行 oa.[[ProxyHandler]].[[SetAlgorithm]] 给出的算法步骤。
-
追加 newValues[i] 到 oa.[[ProxyHandler]].[[BackingList]]。
-
-
返回
undefined 。
-
-
-
令 idlValue 按如下方式确定:
-
使用 idlObject 作为 this 并使用 idlValue 作为给定值,执行 attribute 的设置器步骤。
-
返回
undefined
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
令 name 为在 id 前加上字符串 "
set
" 的结果。 -
执行 SetFunctionName(F, name)。
-
执行 SetFunctionLength(F, 1)。
-
返回 F。
注意: 尽管IDL属性只有一个属性,但由于访问器属性的getter和setter传递了this值,用于访问与IDL属性对应的对象上的属性,因此它们能够暴露特定实例的数据。
注意: 尝试给一个对应于只读的属性赋值时,其行为会根据脚本是否处于严格模式而有所不同。在严格模式下,这样的赋值将导致抛出TypeError
错误。而在非严格模式下,赋值操作将被忽略。
3.7.7. 操作
对于接口上定义的每个暴露的操作的唯一标识符,
都存在一个对应的属性。静态操作在接口对象上公开。常规操作在接口原型对象上公开,
除非该操作是不可伪造的或者
接口是用 [Global
] 扩展属性声明的,
在这种情况下,它们在每个实现该接口的对象上公开。
-
-
令 method 为给定 op、definition 和 realm 创建操作函数的结果。
-
如果 op 是不可伪造的,则令 modifiable 为
false ,否则为true 。 -
令 desc 为 PropertyDescriptor{[[Value]]: method, [[Writable]]: modifiable, [[Enumerable]]:
true , [[Configurable]]: modifiable}。 -
令 id 为 op 的标识符。
-
执行 ! DefinePropertyOrThrow(target, id, desc)。
-
令 id 为 op 的标识符。
-
令 steps 为给定函数参数值 args 的以下系列步骤:
-
尝试运行以下步骤:
-
令 idlObject 为 null。
-
令 n 为 args 的大小。
-
针对常规操作(如果 op 是常规操作)或静态操作(如果 op 是静态操作), 在 target 上使用标识符 id 和参数计数 n,计算有效重载集,并令 S 为结果。
-
令 <operation, values> 为将 S 和 args 传递给重载解析算法的结果。
-
令 R 为
null 。 -
否则,令 R 为使用 idlObject 作为 this 并使用 values 作为参数值运行 operation 的方法步骤的结果。
-
返回 R,转换为 JavaScript 值。
假设 R 是 op 声明要返回的类型的 IDL 值。[whatwg/webidl 问题 #674]
-
然后,如果抛出了异常 E:
-
如果 op 的返回类型是promise 类型,则返回 ! Call(
%Promise.reject%
,%Promise%
, «E»)。 -
否则,结束这些步骤并允许异常传播。
-
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, id)。
-
针对常规操作(如果 op 是常规操作)或静态操作(如果 op 是静态操作), 在 target 上使用标识符 id 和参数计数 0,计算有效重载集,并令 S 为结果。
-
令 length 为 S 中条目中最短参数列表的长度。
-
执行 SetFunctionLength(F, length)。
-
返回 F。
3.7.7.1. 默认操作
如果常规操作的具有默认方法步骤,其标识符会出现在下表的第一列中。在这种情况下,其默认方法步骤由第二列链接的算法给出,操作必须具有表中第三列给出的返回类型。
标识符 | 默认方法步骤 | 返回类型 |
---|---|---|
"toJSON " |
默认 toJSON 步骤 | object
|
没有默认方法步骤的常规操作不得与 [Default
] 扩展属性
一起声明。
3.7.7.1.1. 默认 toJSON 操作
接口 I 的默认 toJSON 步骤如下:
-
令 map 为一个新的有序映射。
-
给定this、stack 和 map,调用收集继承堆栈的属性值。
-
令 result 为 OrdinaryObjectCreate(
%Object.prototype%
)。 -
对于 map 中的每个 key → value,
-
令 k 为转换为 JavaScript 值的 key。
-
令 v 为转换为 JavaScript 值的 value。
-
执行 ! CreateDataPropertyOrThrow(result, k, v)。
-
-
返回 result。
给定一个平台对象 object、一个堆栈 stack 和一个有序映射 map,收集继承堆栈的属性值:
-
令 I 为从 stack 弹出的结果。
-
给定 object、I 和 map,调用收集属性值。
-
如果 stack 不为空,则给定 object、stack 和 map,调用收集继承堆栈的属性值。
为接口 I 创建继承堆栈, 请执行以下步骤:
只有声明了带有 toJSON
操作的 [Default
] 扩展属性
的接口的常规属性才会被包含,即使某个继承接口声明了这样的
toJSON
操作。例如,考虑以下IDL 片段:
[Exposed=Window] interface A { [Default] object toJSON(); attribute DOMString a; }; [Exposed=Window] interface B : A { attribute DOMString b; }; [Exposed=Window] interface C : B { [Default] object toJSON(); attribute DOMString c; };
调用上面定义的实现接口 C
的对象的 toJSON()
方法将返回以下 JSON 对象:
{ "a" : "..." , "c" : "..." }
调用上面定义的实现接口 A
(或 B
)的对象的 toJSON()
方法将返回:
{ "a" : "..." }
还可以在接口混入(或部分接口)上声明
toJSON
操作,其效果等同于在原始接口上声明。例如,考虑以下IDL 片段:
[Exposed=Window] interface D { attribute DOMString d; }; interface mixin M { [Default] object toJSON(); attribute DOMString m; }; D includes M;
调用上面定义的实现接口 D
的对象的 toJSON()
方法将返回:
{ "d" : "..." , "m" : "..." }
3.7.8. 字符串化器
如果接口有一个暴露的字符串化器, 那么必须存在一个具有以下特征的属性:
-
该属性的名称是 "
toString
"。 -
如果字符串化器在接口上是不可伪造的, 或者如果接口是用 [
Global
] 扩展属性声明的, 那么该属性存在于每个实现该接口的对象上。 否则,该属性存在于接口原型对象上。 -
该属性具有属性 { [[Writable]]: B, [[Enumerable]]:
true , [[Configurable]]: B }, 其中如果字符串化器在接口上是不可伪造的,则 B 为false , 否则为true 。 -
函数对象的
length
属性的值是数字值0 。 -
函数对象的
name
属性的值是字符串值 "toString
"。
3.7.9. 可迭代声明
-
如果 definition 具有索引属性获取器,则:
-
执行 DefineMethodProperty(target,
%Symbol.iterator%
,%Array.prototype.values%
, false)。 -
如果 definition 具有值迭代器,则:
-
执行 ! CreateDataPropertyOrThrow(target, "
entries
",%Array.prototype.entries%
)。 -
执行 ! CreateDataPropertyOrThrow(target, "
keys
",%Array.prototype.keys%
)。 -
执行 ! CreateDataPropertyOrThrow(target, "
values
",%Array.prototype.values%
)。 -
执行 ! CreateDataPropertyOrThrow(target, "
forEach
",%Array.prototype.forEach%
)。
-
-
-
否则,如果 definition 具有对迭代器,则:
-
定义
%Symbol.iterator%
和entries
方法:-
令 steps 为以下系列步骤:
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, "
entries
")。 -
执行 SetFunctionLength(F, 0)。
-
执行 DefineMethodProperty(target,
%Symbol.iterator%
, F, false)。 -
执行 ! CreateDataPropertyOrThrow(target, "
entries
", F)。
-
-
定义
keys
方法:-
令 steps 为以下系列步骤:
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, "
keys
")。 -
执行 SetFunctionLength(F, 0)。
-
执行 ! CreateDataPropertyOrThrow(target, "
keys
", F)。
-
-
定义
values
方法:-
令 steps 为以下系列步骤:
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, "
values
")。 -
执行 SetFunctionLength(F, 0)。
-
执行 ! CreateDataPropertyOrThrow(target, "
values
", F)。
-
-
定义
forEach
方法:-
令 steps 为给定函数参数值 callback 和 thisArg 的以下系列步骤:
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, "
forEach
")。 -
执行 SetFunctionLength(F, 1)。
-
执行 ! CreateDataPropertyOrThrow(target, "
forEach
", F)。
-
-
3.7.9.1. 默认迭代器对象
给定接口、目标和迭代种类的默认迭代器对象是一个对象,其 [[Prototype]] 内部插槽是该接口的迭代器原型对象。
默认迭代器对象具有三个内部值:
-
其目标,这是一个其值将被迭代的对象,
-
其种类,即迭代种类,
-
其索引,即要迭代的值的当前索引。
注意: 默认迭代器对象仅用于对迭代器;值迭代器,由于它们目前仅限于迭代对象的支持的索引属性, 因此使用标准的 JavaScript 数组迭代器对象。
注意: 默认迭代器对象没有类字符串;当在给定接口的默认迭代器对象上调用 Object.prototype.toString()
时,将使用该接口的迭代器原型对象的类字符串。
3.7.9.2. 迭代器原型对象
给定接口的迭代器原型对象是一个对象,它存在于每个具有对迭代器的接口中。它充当该接口的默认迭代器对象的原型。
迭代器原型对象的 [[Prototype]] 内部插槽必须是 %Iterator.prototype%
。
-
令 result 为由 kind 的值确定的值:
- "
key
" - "
value
" - "
key+value
" -
-
令 idlKey 为 pair 的键。
-
令 idlValue 为 pair 的值。
-
令 key 为将 idlKey 转换为 JavaScript 值的结果。
-
令 value 为将 idlValue 转换为 JavaScript 值的结果。
-
令 array 为 ! ArrayCreate(2)。
-
执行 ! CreateDataPropertyOrThrow(array, "
0
", key)。 -
执行 ! CreateDataPropertyOrThrow(array, "
1
", value)。 -
result 是 array。
-
- "
-
返回 CreateIteratorResultObject(result,
false )。
迭代器原型对象必须具有一个 next
数据属性,其属性为
{ [[Writable]]:
-
令 thisValue 为
this 值。 -
如果 object 是一个平台对象, 则执行安全检查,传递:
-
平台对象 object,
-
标识符 "
next
",以及 -
类型 "
method
"。
-
-
令 index 为 object 的索引。
-
令 kind 为 object 的种类。
-
令 len 为 values 的长度。
-
如果 index 大于或等于 len,则返回 CreateIteratorResultObject(
undefined ,true )。 -
令 pair 为 values 中索引为 index 的条目。
-
将 object 的索引设置为 index + 1。
-
返回 pair 和 kind 的迭代器结果。
给定接口的迭代器原型对象的类字符串是连接接口的标识符和字符串 " Iterator
" 的结果。
3.7.10. 异步可迭代声明
-
如果 definition 没有异步可迭代声明(任何一种),则返回。
-
如果 definition 具有成对异步可迭代声明,则定义
%Symbol.asyncIterator%
和entries
方法:-
令 steps 为给定函数参数值 args 的以下系列步骤:
-
如果 jsValue 是一个平台对象,则执行安全检查, 传递 jsValue、“
%Symbol.asyncIterator%
”和“method
”。 -
令 idlObject 为表示对 jsValue 引用的 IDL 接口类型值。
-
令 idlArgs 为给定 args 转换异步迭代器方法参数的结果。
-
为 definition 创建一个新的默认异步迭代器对象 iterator,其目标为 idlObject,种类为“
key+value
”,且已完成设置为 false。 -
如果存在此类步骤,则使用 idlObject、iterator 和 idlArgs 为 definition 运行异步迭代器初始化步骤。
-
返回 iterator。
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, "
entries
")。 -
执行 SetFunctionLength(F, 0)。
-
执行 DefineMethodProperty(target,
%Symbol.asyncIterator%
, F, false)。 -
执行 ! CreateDataPropertyOrThrow(target, "
entries
", F)。
-
-
如果 definition 具有成对异步可迭代声明,则定义
keys
方法:-
令 steps 为给定函数参数值 args 的以下系列步骤:
-
令 idlObject 为表示对 jsValue 引用的 IDL 接口类型值。
-
令 idlArgs 为给定 args 转换异步迭代器方法参数的结果。
-
为 definition 创建一个新的默认异步迭代器对象 iterator,其目标为 idlObject,种类为“
key
”,且已完成设置为 false。 -
如果存在此类步骤,则使用 idlObject、iterator 和 idlArgs 为 definition 运行异步迭代器初始化步骤。
-
返回 iterator。
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, "
keys
")。 -
执行 SetFunctionLength(F, 0)。
-
执行 ! CreateDataPropertyOrThrow(target, "
keys
", F)。
-
-
定义
values
方法,可能还定义%Symbol.asyncIterator%
方法:-
令 steps 为给定函数参数值 args 的以下系列步骤:
-
令 idlObject 为表示对 jsValue 引用的 IDL 接口类型值。
-
令 idlArgs 为给定 args 转换异步迭代器方法参数的结果。
-
为 definition 创建一个新的默认异步迭代器对象 iterator,其目标为 idlObject,种类为“
value
”,且已完成设置为 false。 -
如果存在此类步骤,则使用 idlObject、iterator 和 idlArgs 为 definition 运行异步迭代器初始化步骤。
-
返回 iterator。
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, "
values
")。 -
执行 SetFunctionLength(F, 0)。
-
执行 ! CreateDataPropertyOrThrow(target, "
values
", F)。 -
如果 definition 具有值异步可迭代声明,则执行 ! DefineMethodProperty(target,
%Symbol.asyncIterator%
, F, false)。
-
-
令 idlArgs 为一个空列表。
-
令 i 为 0。
-
当 i < argCount 时:
-
返回 idlArgs。
这本质上是针对不允许重载且所有参数都是可选的情况的重载解析算法的超特殊化。
3.7.10.1. 默认异步迭代器对象
给定接口、目标和迭代种类的默认异步迭代器对象是一个对象,其 [[Prototype]] 内部插槽是该接口的异步迭代器原型对象。
默认异步迭代器对象具有内部值:
-
其目标,这是一个其值将被迭代的对象,
-
其种类,即迭代种类,
-
其进行中的 Promise,它是一个
Promise
或 null, -
其已完成,它是一个布尔值。
注意: 默认异步迭代器对象没有类字符串;当在给定接口的默认异步迭代器对象上调用 Object.prototype.toString()
时,将使用该接口的异步迭代器原型对象的类字符串。
3.7.10.2. 异步迭代器原型对象
给定接口的异步迭代器原型对象是一个对象,它存在于每个具有异步可迭代声明的接口中。 它充当该接口的默认异步迭代器对象的原型。
异步迭代器原型对象的 [[Prototype]] 内部插槽必须是 %AsyncIteratorPrototype%
。
异步迭代器原型对象必须具有一个 next
数据属性,其属性为 { [[Writable]]:
-
令 thisValidationPromiseCapability 为 ! NewPromiseCapability(
%Promise%
)。 -
令 thisValue 为
this 值。 -
令 object 为 Completion(ToObject(thisValue))。
-
IfAbruptRejectPromise(object, thisValidationPromiseCapability)。
-
-
平台对象 object,
-
标识符 "
next
",以及 -
类型 "
method
"。
如果这抛出了一个异常 e,则:
-
-
如果 object 不是 interface 的默认异步迭代器对象,则:
-
令 nextSteps 为以下步骤:
-
令 nextPromiseCapability 为 ! NewPromiseCapability(
%Promise%
)。 -
如果 object 的已完成为 true,则:
-
令 result 为 CreateIteratorResultObject(
undefined ,true )。 -
执行 ! Call(nextPromiseCapability.[[Resolve]],
undefined , « result »)。 -
返回 nextPromiseCapability.[[Promise]]。
-
-
令 kind 为 object 的种类。
-
令 fulfillSteps 为给定 next 的以下步骤:
-
将 object 的进行中的 Promise设置为 null。
-
如果 next 是迭代结束,则:
-
将 object 的已完成设置为 true。
-
返回 CreateIteratorResultObject(
undefined ,true )。
-
-
否则,如果 interface 具有成对异步可迭代声明:
-
否则:
-
断言:interface 具有值异步可迭代声明。
-
断言:next 是声明中出现的类型的值。
-
令 value 为 next,转换为 JavaScript 值。
-
返回 CreateIteratorResultObject(value,
false )。
-
-
-
令 onFulfilled 为 CreateBuiltinFunction(fulfillSteps, « »)。
-
令 rejectSteps 为给定 reason 的以下步骤:
-
将 object 的进行中的 Promise设置为 null。
-
将 object 的已完成设置为 true。
-
抛出 reason。
-
-
令 onRejected 为 CreateBuiltinFunction(rejectSteps, « »)。
-
执行 PerformPromiseThen(nextPromise, onFulfilled, onRejected, nextPromiseCapability)。
-
返回 nextPromiseCapability.[[Promise]]。
-
-
令 ongoingPromise 为 object 的进行中的 Promise。
-
如果 ongoingPromise 不为 null,则:
-
令 afterOngoingPromiseCapability 为 ! NewPromiseCapability(
%Promise%
)。 -
令 onSettled 为 CreateBuiltinFunction(nextSteps, « »)。
-
执行 PerformPromiseThen(ongoingPromise, onSettled, onSettled, afterOngoingPromiseCapability)。
-
将 object 的进行中的 Promise设置为 afterOngoingPromiseCapability.[[Promise]]。
-
-
否则:
-
将 object 的进行中的 Promise设置为运行 nextSteps 的结果。
-
-
返回 object 的进行中的 Promise。
如果为接口定义了异步迭代器返回算法,则异步迭代器原型对象必须具有一个 return
数据属性,其属性为 { [[Writable]]:
-
令 returnPromiseCapability 为 ! NewPromiseCapability(
%Promise%
)。 -
令 thisValue 为
this 值。 -
令 object 为 Completion(ToObject(thisValue))。
-
IfAbruptRejectPromise(object, returnPromiseCapability)。
-
-
平台对象 object,
-
标识符 "
return
",以及 -
类型 "
method
"。
如果这抛出了一个异常 e,则:
-
-
如果 object 不是 interface 的默认异步迭代器对象,则:
-
令 returnSteps 为以下步骤:
-
令 returnPromiseCapability 为 ! NewPromiseCapability(
%Promise%
)。 -
如果 object 的已完成为 true,则:
-
令 result 为 CreateIteratorResultObject(value,
true )。 -
执行 ! Call(returnPromiseCapability.[[Resolve]],
undefined , « result »)。 -
返回 returnPromiseCapability.[[Promise]]。
-
-
将 object 的已完成设置为 true。
-
-
令 ongoingPromise 为 object 的进行中的 Promise。
-
如果 ongoingPromise 不为 null,则:
-
令 afterOngoingPromiseCapability 为 ! NewPromiseCapability(
%Promise%
)。 -
令 onSettled 为 CreateBuiltinFunction(returnSteps, « »)。
-
执行 PerformPromiseThen(ongoingPromise, onSettled, onSettled, afterOngoingPromiseCapability)。
-
将 object 的进行中的 Promise设置为 afterOngoingPromiseCapability.[[Promise]]。
-
-
否则:
-
将 object 的进行中的 Promise设置为运行 returnSteps 的结果。
-
-
令 fulfillSteps 为以下步骤:
-
返回 CreateIteratorResultObject(value,
true )。
-
-
令 onFulfilled 为 CreateBuiltinFunction(fulfillSteps, « »)。
-
执行 PerformPromiseThen(object 的进行中的 Promise, onFulfilled,
undefined , returnPromiseCapability)。 -
返回 returnPromiseCapability.[[Promise]]。
给定接口的异步迭代器原型对象的类字符串是连接接口的标识符和字符串
" AsyncIterator
" 的结果。
3.7.11. 类 Map 声明
如果接口 A 使用类 Map 声明进行声明, 那么在 A 的接口原型对象上存在许多附加属性。 这些附加属性将在下面的小节中描述。
3.7.11.1. size
在 A 的接口原型对象上必须存在一个 size
属性,具有以下特征:
-
该属性具有属性 { [[Get]]: G, [[Enumerable]]:
true , [[Configurable]]:true }, 其中 G 是接口的map 大小获取器, 定义如下。 -
-
令 O 为
this 值,并根据 A 使用标识符 "size
" 和类型 "getter
" 进行实现检查。 -
令 map 为表示对 O 引用的 IDL 值的map 条目。
-
返回 map 的大小,转换为 JavaScript 值。
函数对象的
length
属性的值是数字值0 。函数对象的
name
属性的值是字符串值 "get size
"。 -
3.7.11.2. %Symbol.iterator%
在 A 的接口原型对象上必须存在一个数据属性,其名称为 %Symbol.iterator%
符号,属性为 {
[[Writable]]: entries
属性值的函数对象。
key+value
"、"key
" 或 "value
")创建一个 map 迭代器:
-
令 closure 为一个新的抽象闭包,它没有参数,捕获 map 和 kind,并在调用时执行以下步骤:
-
对于 map 中的每个 key → value:
-
将 key 和 value 设置为每个转换为 JavaScript 值的结果。
-
如果 kind 是 "
key
",则令 result 为 key。 -
否则,如果 kind 是 "
value
",则令 result 为 value。 -
否则,令 result 为 CreateArrayFromList(« key, value »)。
-
执行 ? GeneratorYield(CreateIteratorResultObject(result,
false ))。
-
-
返回
undefined 。
-
-
返回 CreateIteratorFromClosure(closure, "
%MapIteratorPrototype%
",%MapIteratorPrototype%
)。
3.7.11.3. entries
在 A 的接口原型对象上必须存在一个 entries
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
-
令 O 为
this 值,并根据 A 使用标识符 "entries
" 和类型 "method
" 进行实现检查。 -
令 map 为表示对 O 引用的 IDL 值的map 条目。
-
返回从 map 创建 map 迭代器的结果,种类为 "
key+value
"。
-
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "entries
"。
3.7.11.4. keys
在 A 的接口原型对象上必须存在一个 keys
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
-
令 O 为
this 值,并根据 A 使用标识符 "keys
" 和类型 "method
" 进行实现检查。 -
令 map 为表示对 O 引用的 IDL 值的map 条目。
-
返回从 map 创建 map 迭代器的结果,种类为 "
key
"。
-
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "keys
"。
3.7.11.5. values
在 A 的接口原型对象上必须存在一个 values
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
-
令 O 为
this 值,并根据 A 使用标识符 "values
" 和类型 "method
" 进行实现检查。 -
令 map 为表示对 O 引用的 IDL 值的map 条目。
-
返回从 map 创建 map 迭代器的结果,种类为 "
value
"。
-
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "values
"。
3.7.11.6. forEach
在 A 的接口原型对象上必须存在一个 forEach
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
-
令 O 为
this 值,并根据 A 使用标识符 "forEach
" 和类型 "method
" 进行实现检查。 -
令 map 为表示对 O 引用的 IDL 值的map 条目。
-
令 callbackFn 为传递给函数的第一个参数,如果未提供,则为
undefined 。 -
如果 IsCallable(callbackFn) 为
false ,则抛出一个TypeError
。 -
令 thisArg 为传递给函数的第二个参数,如果未提供,则为
undefined 。 -
对于 map 中的每个 key → value:
-
令 jsKey 和 jsValue 为 key 和 value 转换为 JavaScript 值的结果。
-
-
返回
undefined 。
-
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "forEach
"。
3.7.11.7. get
在 A 的接口原型对象上必须存在一个 get
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "get
"。
3.7.11.8. has
在 A 的接口原型对象上必须存在一个 has
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "has
"。
3.7.11.9. set
如果 A 没有声明标识符为 "set
" 的成员,
并且 A 是使用读写类 map 声明进行声明的,
那么在 A 的接口原型对象上必须存在一个 set
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
-
令 O 为
this 值,并根据 A 使用标识符 "set
" 和类型 "method
" 进行实现检查。 -
令 map 为表示对 O 引用的 IDL 值的map 条目。
-
令 keyType 为类 map 声明中指定的键类型,valueType 为值类型。
-
令 keyArg 为传递给此函数的第一个参数,如果未提供,则为
undefined 。 -
令 key 为 keyArg 转换为 IDL 值,类型为 keyType。
-
如果 key 为 -0,则将 key 设置为 +0。
-
令 valueArg 为传递给此函数的第二个参数,如果未提供,则为
undefined 。 -
令 value 为 valueArg 转换为 IDL 值,类型为 valueType。
-
设置 map[key] 为 value。
-
返回 O。
-
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "set
"。
如果接口确实声明了一个 set
方法,
它应该类似地将 -0 键映射到 +0,
并且必须返回this。
3.7.11.10. delete
如果 A 没有声明标识符为 "delete
" 的成员,
并且 A 是使用读写类 map 声明进行声明的,
那么在 A 的接口原型对象上必须存在一个 delete
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "delete
"。
如果接口确实声明了一个 delete
方法,
它应该类似地将 -0 键映射到 +0,
并且必须返回一个布尔值
,
指示该键是否存在。
3.7.11.11. clear
如果 A 没有声明标识符为 "clear
" 的成员,
并且 A 是使用读写类 map 声明进行声明的,
那么在 A 的接口原型对象上必须存在一个 clear
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "clear
"。
如果接口确实声明了一个 clear
方法,
它必须保留map 条目对象(而不是生成一个新的)
并且必须返回 undefined
。
3.7.12. 类 Set 声明
如果接口 A 使用类 Set 声明进行声明, 那么在 A 的接口原型对象上存在许多附加属性。 这些附加属性将在下面的小节中描述。
3.7.12.1. size
在 A 的接口原型对象上必须存在一个 size
属性,具有以下特征:
-
该属性具有属性 { [[Get]]: G, [[Enumerable]]:
true , [[Configurable]]:true }, 其中 G 是接口的set 大小获取器, 定义如下。 -
-
令 O 为
this 值,并根据 A 使用标识符 "size
" 和类型 "getter
" 进行实现检查。 -
令 set 为表示对 O 引用的 IDL 值的set 条目。
-
返回 set 的大小, 转换为 JavaScript 值。
函数对象的
length
属性的值是数字值0 。函数对象的
name
属性的值是字符串值 "get size
"。 -
3.7.12.2. %Symbol.iterator%
在 A 的接口原型对象上必须存在一个数据属性,其名称为 %Symbol.iterator%
符号,属性为 {
[[Writable]]: values
属性值的函数对象。
key+value
" 或
"value
")创建一个 set 迭代器:
-
令 closure 为一个新的抽象闭包,它没有参数,捕获 set 和 kind,并在调用时执行以下步骤:
-
对于 set 中的每个 entry:
-
将 entry 设置为 entry 转换为 JavaScript 值的结果。
-
如果 kind 是 "
value
",则令 result 为 entry。 -
否则,令 result 为 CreateArrayFromList(« entry, entry »)。
-
执行 ? GeneratorYield(CreateIteratorResultObject(result,
false ))。
-
-
返回
undefined 。
-
-
返回 CreateIteratorFromClosure(closure, "
%SetIteratorPrototype%
",%SetIteratorPrototype%
)。
3.7.12.3. entries
在 A 的接口原型对象上必须存在一个 entries
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
-
令 O 为
this 值,并根据 A 使用标识符 "entries
" 和类型 "method
" 进行实现检查。 -
令 set 为表示对 O 引用的 IDL 值的set 条目。
-
返回从 set 创建 set 迭代器的结果,种类为 "
key+value
"。
-
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "entries
"。
3.7.12.4. keys
在 A 的接口原型对象上必须存在一个 keys
数据属性,属性为 {
[[Writable]]: values
属性值的函数对象。
3.7.12.5. values
在 A 的接口原型对象上必须存在一个 values
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
-
令 O 为
this 值,并根据 A 使用标识符 "values
" 和类型 "method
" 进行实现检查。 -
令 set 为表示对 O 引用的 IDL 值的set 条目。
-
返回从 set 创建 set 迭代器的结果,种类为 "
value
"。
-
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "values
"。
3.7.12.6. forEach
在 A 的接口原型对象上必须存在一个 forEach
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
-
令 O 为
this 值,并根据 A 使用标识符 "forEach
" 和类型 "method
" 进行实现检查。 -
令 set 为表示对 O 引用的 IDL 值的set 条目。
-
令 callbackFn 为传递给函数的第一个参数,如果未提供,则为
undefined 。 -
如果 IsCallable(callbackFn) 为
false ,则抛出一个TypeError
。 -
令 thisArg 为传递给函数的第二个参数,如果未提供,则为
undefined 。 -
对于 set 中的每个 value:
-
令 jsValue 为 value 转换为 JavaScript 值的结果。
-
-
返回
undefined 。
-
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "forEach
"。
3.7.12.7. has
在 A 的接口原型对象上必须存在一个 has
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "has
"。
3.7.12.8. add
如果 A 没有声明标识符为 "add
" 的成员,
并且 A 是使用读写类 set 声明进行声明的,
那么在 A 的接口原型对象上必须存在一个 add
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "add
"。
如果接口确实声明了一个 add
方法,
它应该类似地将 -0 值映射到 +0,
并且必须返回已设置的值。
3.7.12.9. delete
如果 A 没有声明标识符为 "delete
" 的成员,
并且 A 是使用读写类 set 声明进行声明的,
那么在 A 的接口原型对象上必须存在一个 delete
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "delete
"。
如果接口确实声明了一个 delete
方法,
它应该类似地将 -0 值映射到 +0,
并且必须返回一个布尔值
,
指示该值是否存在。
3.7.12.10. clear
如果 A 没有声明标识符为 "clear
" 的成员,
并且 A 是使用读写类 set 声明进行声明的,
那么在 A 的接口原型对象上必须存在一个 clear
数据属性,具有以下特征:
-
该属性具有属性 { [[Writable]]:
true , [[Enumerable]]:true , [[Configurable]]:true }。 -
该属性的值是一个内置函数对象,其调用时的行为如下:
函数对象的 length
属性的值是数字值
函数对象的 name
属性的值是字符串值 "clear
"。
如果接口确实声明了一个 clear
方法,
它必须保留set 条目对象(而不是生成一个新的)
并且必须返回 undefined
。
3.8. 实现接口的平台对象
规范可能会以各种方式引用概念“object 实现 interface”,包括“object 是一个 interface 对象”。
每个平台对象都与一个领域相关联,就像初始对象一样。 此领域存储在平台对象的 [[Realm]] 插槽中。 使用 Web IDL 的规范有责任说明每个平台对象与哪个领域(或者,通过代理,哪个全局对象)相关联。 特别是,下面的算法将新的平台对象与作为参数给出的领域相关联。
-
返回内部创建实现 interface 的新对象的结果,使用 realm 和
undefined 。
-
断言:interface 在 realm 中公开。
-
如果 newTarget 是
undefined ,则:-
令 prototype 为 realm 中 interface 的接口原型对象。
-
-
否则:
-
断言:IsCallable(newTarget) 为 true。
-
如果 prototype 不是对象,则:
-
令 targetRealm 为 ? GetFunctionRealm(newTarget)。
-
将 prototype 设置为 targetRealm 中 interface 的接口原型对象。
-
-
-
令 slots 为 « [[Prototype]], [[Extensible]], [[Realm]], [[PrimaryInterface]] »。
-
如果 interface 是
DOMException
,则将 [[ErrorData]] 附加到 slots。 -
令 instance 为 MakeBasicObject(slots)。
-
将 instance.[[Realm]] 设置为 realm。
-
将 instance.[[PrimaryInterface]] 设置为 interface。
-
将 instance.[[Prototype]] 设置为 prototype。
-
令 interfaces 为 interface 的包含继承接口。
-
如果 interface 使用 [
Global
] 扩展属性声明,则:-
在 instance 上定义 interface 的常规操作,给定 realm。
-
在 instance 上定义 interface 的常规属性,给定 realm。
-
在 instance 上定义 interface 的迭代方法,给定 realm。
-
在 instance 上定义 interface 的异步迭代方法,给定 realm。
-
在 instance 上定义全局属性引用,给定 realm。
-
将 instance.[[SetPrototypeOf]] 设置为 § 3.8.1 [[SetPrototypeOf]] 中定义的。
-
-
否则,如果 interfaces 包含一个接口,该接口支持索引属性、命名属性或两者都支持:
-
将 instance.[[GetOwnProperty]] 设置为 § 3.9.1 [[GetOwnProperty]] 中定义的。
-
将 instance.[[Set]] 设置为 § 3.9.2 [[Set]] 中定义的。
-
将 instance.[[DefineOwnProperty]] 设置为 § 3.9.3 [[DefineOwnProperty]] 中定义的。
-
将 instance.[[Delete]] 设置为 § 3.9.4 [[Delete]] 中定义的。
-
将 instance.[[PreventExtensions]] 设置为 § 3.9.5 [[PreventExtensions]] 中定义的。
-
将 instance.[[OwnPropertyKeys]] 设置为 § 3.9.6 [[OwnPropertyKeys]] 中定义的。
-
-
返回 instance。
-
对 interfaces 进行排序,使得如果 A 和 B 是 interfaces 的项, 并且 A 继承自 B,则 A 在 interfaces 中的索引高于 B。
-
对于 interfaces 中的每个 interface:
-
如果 interface 未使用 [
LegacyNoInterfaceObject
] 或 [LegacyNamespace
] 扩展属性声明,则:-
令 id 为 interface 的标识符。
-
令 interfaceObject 为在 realm 中使用 id 为 interface 创建接口对象的结果。
-
执行 DefineMethodProperty(target, id, interfaceObject, false)。
-
如果 interface 使用 [
LegacyWindowAlias
] 扩展属性声明, 并且 target 实现Window
接口,则:-
对于 [
LegacyWindowAlias
] 的 标识符中的每个标识符 id:-
执行 DefineMethodProperty(target, id, interfaceObject, false)。
-
-
-
-
如果 interface 使用 [
LegacyFactoryFunction
] 扩展属性声明, 则:-
对于 [
LegacyFactoryFunction
] 的 标识符中的每个标识符 id:-
令 legacyFactoryFunction 为在 realm 中为 interface 使用 id 创建旧式工厂函数的结果。
-
执行 DefineMethodProperty(target, id, legacyFactoryFunction, false)。
-
-
-
-
对于在 realm 中公开并且定义了常量的每个回调接口 interface:
-
令 id 为 interface 的标识符。
-
令 interfaceObject 为在 realm 中使用 id 为 interface 创建旧式回调接口对象的结果。
-
执行 DefineMethodProperty(target, id, interfaceObject, false)。
-
-
对于在 realm 中公开的每个命名空间 namespace:
-
令 id 为 namespace 的标识符。
-
令 namespaceObject 为在 realm 中为 namespace 创建命名空间对象的结果。
-
执行 DefineMethodProperty(target, id, namespaceObject, false)。
-
具有不同全局对象的多个平台对象将在其 [[PrimaryInterface]] 内部插槽中共享对同一接口的引用。例如,一个页面可以包含一个同源 iframe,iframe 的方法可以在主页面的同类元素上调用,而不会引发异常。
接口混入不直接参与实现算法的评估。相反,接口混入包含的每个接口都有其自己的接口混入的每个成员的“副本”,并且相应的操作函数检查接收者实现包含接口混入的特定接口。
给定平台对象关联的领域可以在创建后更改。当与平台对象关联的领域更改时,其 [[Prototype]] 内部插槽必须立即更新为平台对象新关联的领域中主接口的接口原型对象。
此外,实现具有 [Global
] 扩展属性的接口的平台对象会从以下位置声明性地获取属性:
而应以命令方式定义这些属性。
3.8.1. [[SetPrototypeOf]]
当使用 JavaScript 语言值 V 调用实现带有 [Global
] 扩展属性的接口的平台对象 O 的 [[SetPrototypeOf]] 内部方法时,将执行以下步骤:
-
如果 O 的关联领域的全局原型链是否可变为 true, 则返回 ? OrdinarySetPrototypeOf(O, V)。
-
返回 ? SetImmutablePrototype(O, V)。
注意:对于 Window
对象,无法观察到此方法是否已实现,因为 WindowProxy
对象的存在确保了 [[SetPrototypeOf]] 永远不会直接在 Window
对象上调用。但是,对于其他全局对象,这是必需的。
3.9. 旧版平台对象
遗留平台对象会显示具有与其索引属性和命名属性对应的附加属性。这些属性并不是对象上的“真实”自有属性,而是通过[[GetOwnProperty]] 内部方法使它们看起来像是自有属性。
一个对象可以实现多个支持索引属性的接口。但是,如果这样做,并且对于对象的支持的属性索引存在冲突定义,则对象看起来具有哪些附加属性或其索引属性的确切行为是未定义的。命名属性的情况同样适用。
由遗留平台对象实现的派生接口上定义的索引属性获取器是定义对象以数组索引进行索引时的行为的获取器。对于索引属性设置器也是如此。这样,来自祖先接口的这些特殊操作的定义可以被覆盖。
如果某个平台对象 O 实现了具有某标识符的接口,且该接口成员在任何 O 实现的接口中为不可伪造,则该属性名称为给定平台对象上的不可伪造属性名称。
对于getter的支持在§ 3.9.1 [[GetOwnProperty]]中处理,而对于setter的支持在§ 3.9.3 [[DefineOwnProperty]]和§ 3.9.2 [[Set]]中处理。
此外,遗留平台对象还具有以下定义的内部方法:
3.9.1. [[GetOwnProperty]]
每个遗留平台对象 O 的 [[GetOwnProperty]] 内部方法在被调用时,传入属性名称 P,必须按如下行为执行:
-
返回 ? LegacyPlatformObjectGetOwnProperty(O, P,
false )。
3.9.2. [[Set]]
每个遗留平台对象 O 的 [[Set]] 内部方法在被调用时,传入属性名称 P,值 V,以及 JavaScript 语言值 Receiver,必须按如下行为执行:
3.9.3. [[DefineOwnProperty]]
当一个遗留平台对象 O 的 [[DefineOwnProperty]] 内部方法被调用时,传入属性键 P 和 属性描述符 Desc,应按以下步骤进行:
-
-
如果调用 IsDataDescriptor(Desc) 的结果是
false ,则返回false 。 -
如果 O 没有实现具有索引属性设置器的接口,则返回
false 。 -
调用索引属性设置器,传入 O,P 和 Desc.[[Value]]。
-
返回
true 。
-
-
如果 O 支持命名属性,O 没有实现带有 [
Global
] 扩展属性的接口,P 是一个字符串, 并且 P 不是 O 的不可伪造属性名, 那么:-
如果 P 不是支持的属性名,则设 creating 为 true,否则设为 false。
-
如果 O 实现了具有 [
LegacyOverrideBuiltIns
] 扩展属性 的接口,或 O 没有名为 P 的自有属性,则:-
如果 creating 为 false 并且 O 没有实现具有 命名属性设置器 的接口,则返回
false 。 -
-
如果调用 IsDataDescriptor(Desc) 的结果是
false ,则返回false 。 -
调用命名属性设置器,传入 O,P 和 Desc.[[Value]]。
-
返回
true 。
-
-
-
-
返回 ! OrdinaryDefineOwnProperty(O, P, Desc)。
3.9.4. [[Delete]]
当每个遗留平台对象 O 的 [[Delete]] 内部方法被调用时,传入属性名称 P,应按以下步骤进行。
3.9.5. [[PreventExtensions]]
当遗留平台对象的 [[PreventExtensions]] 内部方法被调用时,执行以下步骤:
-
返回
false 。
注意:这使得遗留平台对象保持可扩展性,因为对它们来说 [[PreventExtensions]] 会失败。
3.9.6. [[OwnPropertyKeys]]
本文档没有为实现接口的平台对象(或代表异常的平台对象)定义完整的属性枚举顺序。 然而,它通过如下定义 [[OwnPropertyKeys]] 内部方法为旧版平台对象定义了该顺序。
当调用旧版平台对象 O 的 [[OwnPropertyKeys]] 内部方法时, 将执行以下步骤:
3.9.7. 抽象操作
要确定属性名 P 是否是数组索引,应用以下算法:
-
如果 P 不是字符串,则返回
false 。 -
设 index 为 CanonicalNumericIndexString(P)。
-
如果 index 是
undefined ,则返回false 。 -
如果 IsInteger(index) 是
false ,则返回false 。 -
如果 index 是 −0,则返回
false 。 -
如果 index < 0,则返回
false 。 -
如果 index ≥ 232 − 1,则返回
false 。注意: 232 − 1 是 JavaScript 允许的最大数组长度。
-
返回
true 。
命名属性可见性算法用于确定给定的命名属性是否在对象上公开。某些命名属性是否公开取决于是否使用了 [LegacyOverrideBuiltIns
]
扩展属性。该算法如下操作,属性名为 P,对象为 O:
-
如果 P 不是 O 的一个 受支持的属性名称,则返回 false。
-
如果 O 有一个名为 P 的自身属性,则返回 false。
注意:这将包括 O 具有不可伪造属性的情况,因为实际上这些属性总是在对象有任何受支持的属性名称之前设置的,一旦设置,它们将使相应的命名属性不可见。
-
如果 O 实现了一个具有 [
LegacyOverrideBuiltIns
] 扩展属性 的接口,则返回 true。 -
设 prototype 为 O.[[GetPrototypeOf]]()。
-
当 prototype 不为 null 时:
-
如果 prototype 不是一个 命名属性对象,并且 prototype 有一个名为 P 的自身属性,则返回 false。
-
将 prototype 设置为 prototype.[[GetPrototypeOf]]()。
-
-
返回 true。
这确保了对于具有命名属性的对象,属性解析按照以下顺序进行:
-
索引属性。
-
自身属性,包括不可伪造的属性和操作。
-
然后,如果 [
LegacyOverrideBuiltIns
]:-
命名属性。
-
来自原型链的属性。
-
-
否则,如果不使用 [
LegacyOverrideBuiltIns
]:-
来自原型链的属性。
-
命名属性。
-
要在平台对象 O 上,使用属性名 P 和 JavaScript 值 V,调用索引属性设置器,必须执行以下步骤:
-
如果 index 不是 受支持的属性索引,则设 creating 为 true,否则设为 false。
-
令 operation 为用于声明索引属性设置器的操作。
-
令 T 为 operation 的第二个参数的类型。
-
令 value 为将 V 转换为类型为 T 的 IDL 值的结果,使用 转换。
-
如果 operation 是在没有 标识符 的情况下定义的:
-
如果 creating 为 true,则执行接口描述中列出的步骤,以 index 作为索引,value 作为值来 设置新索引属性的值。
-
否则,creating 为 false。执行接口描述中列出的步骤,以 index 作为索引,value 作为值来 设置现有索引属性的值。
-
-
否则,operation 是用标识符定义的。执行 operation 的 方法步骤,以 O 作为 this,« index, value » 作为参数值。
要在平台对象 O 上,使用属性名 P 和 JavaScript 值 V,调用命名属性设置器,必须执行以下步骤:
-
如果 P 不是 受支持的属性名称,则设 creating 为 true,否则为 false。
-
令 operation 为用于声明命名属性设置器的操作。
-
令 T 为 operation 的第二个参数的类型。
-
令 value 为将 V 转换为类型为 T 的 IDL 值的结果,使用 转换。
-
如果 operation 是在没有 标识符 的情况下定义的:
-
如果 creating 为 true,则执行接口描述中列出的步骤,以 P 作为名称,value 作为值来 设置新命名属性的值。
-
否则,creating 为 false。执行接口描述中列出的步骤,以 P 作为名称,value 作为值来 设置现有命名属性的值。
-
-
否则,operation 是用标识符定义的。执行 operation 的 方法步骤,以 O 作为 this,« P, value » 作为参数值。
LegacyPlatformObjectGetOwnProperty 抽象操作在使用对象 O、属性名 P 和布尔值 ignoreNamedProps 调用时,执行以下步骤:
-
-
如果 index 是 受支持的属性索引,则:
-
令 operation 为用于声明索引属性 getter 的操作。
-
令 value 为一个未初始化的变量。
-
如果 operation 是在没有 标识符 的情况下定义的,则将 value 设为执行接口描述中列出的步骤的结果,用于 确定索引属性的值,索引为 index。
-
否则,operation 是用标识符定义的。将 value 设为执行 operation 的 方法步骤 的结果,以 O 作为 this,« index » 作为参数值。
-
令 desc 为一个新创建的 属性描述符,没有字段。
-
将 desc.[[Value]] 设置为将 value 转换为 JavaScript 值的结果。
-
如果 O 实现 了带有 索引属性 setter 的接口,则将 desc.[[Writable]] 设为
true ,否则设为false 。 -
将 desc.[[Enumerable]] 和 desc.[[Configurable]] 设为
true 。 -
返回 desc。
-
-
将 ignoreNamedProps 设为 true。
-
如果 O 支持命名属性 且 ignoreNamedProps 为 false,则:
-
如果运行 命名属性可见性算法,传入属性名 P 和对象 O,结果为 true,则:
-
令 operation 为用于声明命名属性 getter 的操作。
-
令 value 为一个未初始化的变量。
-
如果 operation 是在没有 标识符 的情况下定义的,则将 value 设为执行接口描述中列出的步骤的结果,用于 确定命名属性的值,名称为 P。
-
否则,operation 是用标识符定义的。将 value 设为执行 operation 的 方法步骤 的结果,以 O 作为 this,« P » 作为参数值。
-
令 desc 为一个新创建的 属性描述符,没有字段。
-
将 desc.[[Value]] 设为 转换 value 为 JavaScript 值的结果。
-
如果 O 实现 了带有 命名属性 setter 的接口,则将 desc.[[Writable]] 设为
true ,否则设为false 。 -
如果 O 实现 了带有 [
LegacyUnenumerableNamedProperties
] 扩展属性 的接口,则将 desc.[[Enumerable]] 设为false ,否则设为true 。 -
将 desc.[[Configurable]] 设为
true 。 -
返回 desc。
-
-
-
返回 OrdinaryGetOwnProperty(O, P)。
3.10. 可观察数组奇异对象
可观察数组的特殊对象是一种特定类型的 JavaScript 代理特殊对象,通过本节定义的代理陷阱创建。它们之所以这样定义,是因为 JavaScript
规范对拥有Array
实例作为代理目标的代理特殊对象进行特殊处理,我们希望确保可观察数组类型以这种特殊处理暴露给
JavaScript 代码。
可观察数组的特殊对象所使用的代理陷阱,旨在确保超出普通Array
实例的若干不变量:
-
数组没有空洞,即在包含范围 0 到
observableArray.length
- 1 内的每个属性都将填充为与指定 Web IDL 类型兼容的值,且该范围之外不存在数组索引属性。 -
重要属性的属性描述符不能从其默认配置更改;索引属性始终保持为可配置、可枚举、可写的数据属性,而
length
属性保持为不可配置、不可枚举、可写的数据属性。 -
无法通过例如
Object.preventExtensions()
来防止向数组添加额外的属性。
-
令 innerArray 为 ! ArrayCreate(0)。
-
令 handler 为 OrdinaryObjectCreate(
null , « [[Type]], [[SetAlgorithm]], [[DeleteAlgorithm]], [[BackingList]] »)。 -
将 handler.[[Type]] 设为 T。
-
将 handler.[[SetAlgorithm]] 设为 setAlgorithm。
-
将 handler.[[DeleteAlgorithm]] 设为 deleteAlgorithm。
-
令 defineProperty 为 CreateBuiltinFunction(§ 3.10.1 defineProperty中的步骤, « », realm)。
-
执行 ! CreateDataPropertyOrThrow(handler, "
defineProperty
", defineProperty)。 -
令 deleteProperty 为 CreateBuiltinFunction(§ 3.10.2 deleteProperty中的步骤, « », realm)。
-
执行 ! CreateDataPropertyOrThrow(handler, "
deleteProperty
", deleteProperty)。 -
令 get 为 CreateBuiltinFunction(§ 3.10.3 get中的步骤, « », realm)。
-
执行 ! CreateDataPropertyOrThrow(handler, "
get
", get)。 -
令 getOwnPropertyDescriptor 为 CreateBuiltinFunction(§ 3.10.4 getOwnPropertyDescriptor中的步骤, « », realm)。
-
执行 ! CreateDataPropertyOrThrow(handler, "
getOwnPropertyDescriptor
", getOwnPropertyDescriptor)。 -
令 has 为 CreateBuiltinFunction(§ 3.10.5 has 中的步骤, « », realm)。
-
执行 ! CreateDataPropertyOrThrow(handler, "
has
", has)。 -
令 ownKeys 为 CreateBuiltinFunction(§ 3.10.6 ownKeys 中的步骤, « », realm)。
-
执行 ! CreateDataPropertyOrThrow(handler, "
ownKeys
", ownKeys)。 -
令 preventExtensions 为 CreateBuiltinFunction(§ 3.10.7 preventExtensions 中的步骤, « », realm)。
-
执行 ! CreateDataPropertyOrThrow(handler, "
preventExtensions
", preventExtensions)。 -
令 set 为 CreateBuiltinFunction(§ 3.10.8 set 中的步骤, « », realm)。
-
执行 ! CreateDataPropertyOrThrow(handler, "
set
", set)。 -
返回 ! ProxyCreate(innerArray, handler)。
3.10.1. defineProperty
对于可观察数组特殊对象,给定 O、P 和
descriptorObj,其 defineProperty
代理陷阱的步骤如下:
-
令 handler 为
this 值。 -
令 descriptor 为 ! ToPropertyDescriptor(descriptorObj)。
-
如果 P 为 "length",则:
-
如果 IsAccessorDescriptor(descriptor) 为
true ,则返回false 。 -
如果 descriptor.[[Configurable]] 存在且值为
true ,则返回false 。 -
如果 descriptor.[[Enumerable]] 存在且值为
true ,则返回false 。 -
如果 descriptor.[[Writable]] 存在且值为
false ,则返回false 。 -
如果 descriptor.[[Value]] 存在,则返回调用设置长度给定 handler 和 descriptor.[[Value]] 的结果。
-
返回
true 。
-
-
如果 P 是一个数组索引,则:
-
如果 IsAccessorDescriptor(descriptor) 为
true ,则返回false 。 -
如果 descriptor.[[Configurable]] 存在且值为
false ,则返回false 。 -
如果 descriptor.[[Enumerable]] 存在且值为
false ,则返回false 。 -
如果 descriptor.[[Writable]] 存在且值为
false ,则返回false 。 -
如果 descriptor.[[Value]] 存在,则返回调用设置索引值给定 handler、P 和 descriptor.[[Value]] 的结果。
-
返回
true 。
-
-
返回 ? O.[[DefineOwnProperty]](P, descriptor)。
3.10.2. deleteProperty
deleteProperty
代理陷阱的步骤如下:
3.10.3.
get
get
代理陷阱的步骤如下:
3.10.4. getOwnPropertyDescriptor
getOwnPropertyDescriptor
代理捕获器的步骤如下:
-
令 handler 为
this 值。 -
令 length 为 handler.[[BackingList]] 的大小。
-
如果 P 是 "length",则返回 ! FromPropertyDescriptor(PropertyDescriptor{[[Configurable]]:
false , [[Enumerable]]:false , [[Writable]]:true , [[Value]]: length })。 -
如果 P 是一个数组索引,则
-
如果 index ≥ length,则返回
undefined 。 -
令 jsValue 为将 handler.[[BackingList]][index] 转换为 JavaScript 值的结果。
-
断言:以上步骤永远不会抛出异常。
-
返回 FromPropertyDescriptor(PropertyDescriptor{[[Configurable]]:
true , [[Enumerable]]:true , [[Writable]]:true , [[Value]]: jsValue })。
-
返回 FromPropertyDescriptor(? O.[[GetOwnProperty]](P))。
3.10.5.
has
has
代理捕获器的步骤如下:
3.10.6.
ownKeys
ownKeys
代理捕获器的步骤如下:
3.10.7. preventExtensions
3.10.8.
set
set
代理捕获器的步骤如下:
3.10.9. 抽象操作
-
如果 uint32Len ≠ numberLen,则抛出
RangeError
异常。 -
令 oldLen 为 handler.[[BackingList]] 的大小。
-
如果 uint32Len > oldLen,则返回
false 。 -
令 indexToDelete 为 oldLen − 1。
-
当 indexToDelete ≥ uint32Len 时:
-
执行 handler.[[DeleteAlgorithm]] 给出的算法步骤,给定 handler.[[BackingList]][indexToDelete] 和 indexToDelete。
-
移除 handler.[[BackingList]] 中的最后一项。
-
将 indexToDelete 设置为 indexToDelete − 1。
-
-
返回
true 。
-
令 oldLen 为 handler.[[BackingList]] 的大小。
-
如果 index > oldLen,返回
false 。 -
令 idlValue 为将 V 转换为 handler.[[Type]] 给出的类型的结果。
-
如果 index < oldLen,则:
-
执行 handler.[[DeleteAlgorithm]] 给出的算法步骤,给定 handler.[[BackingList]][index] 和 index。
-
-
执行 handler.[[SetAlgorithm]] 给出的算法步骤,给定 idlValue 和 index。
-
如果 index = oldLen,则追加 idlValue 到 handler.[[BackingList]]。
-
否则,将 handler.[[BackingList]][index] 设置为 idlValue。
-
返回
true 。
3.11. 回调接口
如 § 2.12 实现接口的对象 中所述,回调接口可以由任何 JavaScript 对象在脚本中实现。 以下情况说明了如何在给定对象上调用回调接口的操作:
注意,JavaScript 对象不需要具有与常量对应的属性,也可以被视为实现了带有常量声明的回调接口。
Web IDL 参数列表是一个由值组成的列表,其中每个值要么是 IDL 值,要么是表示缺失可选参数的特殊值“缺失”。
要调用用户对象的操作,给定一个回调接口类型值 value,操作名称 opName,Web IDL 参数列表 args,以及可选的回调 this 值 thisArg,执行以下步骤。这些步骤将返回一个 IDL 值或抛出一个异常。
-
令 completion 为一个未初始化的变量。
-
如果未提供 thisArg,则将 thisArg 设置为
undefined 。 -
令 O 为与 value 对应的 JavaScript 对象。
-
令 realm 为 O 的关联领域。
-
令 relevant settings 为 realm 的设置对象。
-
令 stored settings 为 value 的回调上下文。
-
使用 relevant settings 准备运行脚本。
-
使用 stored settings 准备运行回调。
-
令 X 为 O。
-
如果 IsCallable(O) 为假,则:
-
令 getResult 为 Completion(Get(O, opName))。
-
如果 getResult 是一个突然完成,则将 completion 设置为 getResult 并跳转到标记为 返回 的步骤。
-
将 X 设置为 getResult.[[Value]]。
-
如果 IsCallable(X) 为
false , 则将 completion 设置为 Completion Record { [[Type]]: throw, [[Value]]: 一个 新创建的TypeError
对象, [[Target]]: empty },并跳转 到标记为 返回 的步骤。 -
将 thisArg 设置为 O (覆盖提供的值)。
-
-
令 jsArgs 为 将 args 转换为 JavaScript 参数列表的结果。如果此步骤抛出异常,则将 completion 设置为表示所抛出异常的完成值,并跳转到标记为返回的步骤。
-
令 callResult 为 Completion(Call(X, thisArg, jsArgs))。
-
如果 callResult 是一个突然完成,则将 completion 设置为 callResult 并跳转到标记为 返回 的步骤。
-
将 completion 设置为将 callResult.[[Value]] 转换为与操作返回类型相同的 IDL 值的结果。如果此操作抛出异常,则将 completion 设置为表示所抛出异常的完成值。
-
返回:此时 completion 将被设置为一个 IDL 值或一个突然完成。
-
使用 stored settings 在运行回调后进行清理。
-
使用 relevant settings 在运行脚本后进行清理。
-
如果 completion 是一个 IDL 值,则返回 completion。
-
如果 completion 是一个突然完成,并且操作的返回类型不是promise 类型,则抛出 completion.[[Value]]。
-
令 rejectedPromise 为 ! Call(
%Promise.reject%
,%Promise%
, «completion.[[Value]]»)。 -
返回将 rejectedPromise 转换为操作返回类型的结果。
-
对于在给定领域中公开且定义了常量的每个回调接口, 在领域的全局对象上存在一个对应的属性。 该属性的名称是回调接口的标识符, 其值是一个称为旧版回调接口对象的对象。
给定回调接口的旧版回调接口对象是一个内置函数对象。 它具有与该接口上定义的常量相对应的属性, 如§ 3.7.5 常量部分所述。
注意:由于旧版回调接口对象是一个函数对象,因此当将 typeof
运算符应用于旧版回调接口对象时,它将返回 "function"。
给定回调接口 interface(其标识符为 id,且位于领域 realm 中),其旧版回调接口对象按如下方式创建:
-
令 steps 为以下步骤:
-
令 F 为 CreateBuiltinFunction(steps, « », realm)。
-
执行 SetFunctionName(F, id)。
-
执行 SetFunctionLength(F, 0)。
-
在给定 realm 的情况下,在 F 上定义 interface 的常量。
-
返回 F。
3.12. 调用回调函数
一个用作回调函数值的 JavaScript 可调用对象的调用方式,与回调接口值上的操作的调用方式类似(如上一节所述)。
要调用一个回调函数类型值
callable,使用 Web IDL 参数列表 args、
异常行为 exceptionBehavior(“report
”或“rethrow
”),
以及可选的回调
this 值 thisArg,
执行以下步骤。
这些步骤将返回一个 IDL 值或抛出一个异常。
exceptionBehavior 参数当且仅当 callable 的返回类型不是promise 类型时才必须提供。如果
callable 的返回类型既不是 undefined
也不是 any
,则它必须是“rethrow
”。
rethrow
”。 -
令 completion 为一个未初始化的变量。
-
如果未给出 thisArg,则令 thisArg 为
undefined 。 -
令 F 为与 callable 对应的 JavaScript 对象。
-
如果 IsCallable(F) 为
false :-
注意:这仅在回调函数来自标记有 [
LegacyTreatNonObjectAsNull
] 的属性时才可能发生。 -
返回将
undefined 转换为回调函数返回类型的结果。
-
-
令 realm 为 F 的关联领域。
-
令 relevant settings 为 realm 的设置对象。
-
令 stored settings 为 callable 的回调上下文。
-
使用 relevant settings 准备运行脚本。
-
使用 stored settings 准备运行回调。
-
令 jsArgs 为将 args 转换为 JavaScript 参数列表的结果。如果此操作抛出异常,则将 completion 设置为表示所抛出异常的完成值,并跳转到标记为 返回 的步骤。
-
令 callResult 为 Completion(Call(F, thisArg, jsArgs))。
-
如果 callResult 是一个突然完成,则将 completion 设置为 callResult 并跳转到标记为 返回 的步骤。
-
将 completion 设置为将 callResult.[[Value]] 转换为与 callable 返回类型相同的 IDL 值的结果。如果此操作抛出异常,则将 completion 设置为表示所抛出异常的完成值。
-
返回:此时 completion 将被设置为一个 IDL 值或一个突然完成。
-
使用 stored settings 在运行回调后进行清理。
-
使用 relevant settings 在运行脚本后进行清理。
-
如果 completion 是一个 IDL 值,则返回 completion。
-
如果 exceptionBehavior 是“
rethrow
”,则抛出 completion.[[Value]]。 -
否则,如果 exceptionBehavior 是“
report
”: -
断言:callable 的返回类型是一个promise 类型。
-
令 rejectedPromise 为 ! Call(
%Promise.reject%
,%Promise%
, «completion.[[Value]]»)。 -
返回将 rejectedPromise 转换为回调函数返回类型的结果。
-
一些回调函数 invece 用作构造函数。此类回调函数的返回类型不得为promise 类型。
要构造一个回调函数类型值 callable,使用 Web IDL 参数列表 args, 执行以下步骤。 这些步骤将返回一个 IDL 值或抛出一个异常。
-
令 completion 为一个未初始化的变量。
-
令 F 为与 callable 对应的 JavaScript 对象。
-
如果 IsConstructor(F) 为
false , 则抛出TypeError
异常。 -
令 realm 为 F 的关联领域。
-
令 relevant settings 为 realm 的设置对象。
-
令 stored settings 为 callable 的回调上下文。
-
使用 relevant settings 准备运行脚本。
-
使用 stored settings 准备运行回调。
-
令 jsArgs 为将 args 转换为 JavaScript 参数列表的结果。如果此操作抛出异常,则将 completion 设置为表示所抛出异常的完成值,并跳转到标记为 返回 的步骤。
-
令 callResult 为 Completion(Construct(F, jsArgs))。
-
如果 callResult 是一个突然完成,则将 completion 设置为 callResult 并跳转到标记为 返回 的步骤。
-
将 completion 设置为将 callResult.[[Value]] 转换为与 callable 返回类型相同的 IDL 值的结果。如果此操作抛出异常,则将 completion 设置为表示所抛出异常的完成值。
-
返回:此时 completion 将被设置为一个 IDL 值或一个突然完成。
-
使用 stored settings 在运行回调后进行清理。
-
使用 relevant settings 在运行脚本后进行清理。
-
如果 completion 是一个突然完成,则抛出 completion.[[Value]]。
-
返回 completion。
-
3.13. 命名空间
对于每一个在给定的命名空间中暴露的领域,在该领域的全局对象上存在相应的属性。该属性的名称为命名空间的标识符,其值是一个称为命名空间对象的对象。
命名空间对象的特性在 § 3.13.1 命名空间对象 中描述。
3.13.1. 命名空间对象
为给定的命名空间 namespace 和领域 realm 创建命名空间对象,步骤如下:
-
令 namespaceObject 为 OrdinaryObjectCreate(realm.[[Intrinsics]].[[
%Object.prototype%
]])。 -
定义 namespace 在 namespaceObject 上的常规属性,给定 realm。
-
定义 namespace 在 namespaceObject 上的常规操作,给定 realm。
-
定义 namespace 在 namespaceObject 上的常量,给定 realm。
-
对于每一个具有 [
LegacyNamespace
] 扩展属性且其参数为 namespace 标识符的 暴露 接口 interface:-
令 id 为 interface 的 标识符。
-
令 interfaceObject 为创建 interface 的接口对象的结果,给定 id 和 realm。
-
执行 DefineMethodProperty(namespaceObject, id, interfaceObject, false)。
-
-
返回 namespaceObject。
3.14. 异常
3.14.1.
DOMException
自定义绑定
在 JavaScript 绑定中,DOMException
的接口原型对象的 [[Prototype]] 内部插槽被设置为内在对象 %Error.prototype%
,
正如在创建接口原型对象抽象操作中所定义的。
它也像所有内置异常一样,拥有一个 [[ErrorData]] 插槽。
此外,如果一个实现赋予了原生的 Error
对象特殊的能力或非标准属性(例如 stack
属性),
它也应该在 DOMException
对象上公开这些能力或属性。
3.14.2. 异常对象
简单异常由相应类型的原生 JavaScript 对象表示。
一个 DOMException
由一个实现了 DOMException
接口的平台对象表示。
3.14.3. 创建和抛出异常
DOMException
,给定一个字符串
name:
-
断言:name 出现在
DOMException
名称表中。 -
令 ex 为一个在当前领域中新创建的
DOMException
。 -
将 ex 的 name 设置为 name。
-
将 ex 的 message 设置为一个适合异常情况的实现定义的消息。调用规范可能包含帮助实现构建此消息的信息。
实现在构建此消息时需要小心,不要泄露敏感或受保护的信息,例如,通过包含跨源框架的 URL 或可能识别用户的信息。
-
返回 ex。
上述算法限制了从函数对象传播出来的表示异常的对象,必须是与该函数对象的领域相关联的对象(即,函数执行时的当前领域)。例如,考虑以下 IDL:
[Exposed =Window ]interface MathUtils { // 如果 x 为负,则抛出 "NotSupportedError" DOMException。double computeSquareRoot (double x ); };
如果我们将 computeSquareRoot
应用于来自不同领域的 MathUtils
对象,那么抛出的异常将来自方法的领域,而不是应用该方法的对象:
const myMU= window. getMathUtils(); // 来自此领域的 MathUtils 对象 const otherMU= otherWindow. getMathUtils(); // 来自不同领域的 MathUtils 对象 myMUinstanceof Object; // 计算结果为 true。 otherMUinstanceof Object; // 计算结果为 false。 otherMUinstanceof otherWindow. Object; // 计算结果为 true。 try { otherMU. doComputation. call( myMU, - 1 ); } catch ( e) { console. assert( ! ( einstanceof DOMException)); console. assert( einstanceof otherWindow. DOMException); }
3.14.4. 处理异常
除非另有规定, 每当由于本文档中的要求而调用 JavaScript 运行时语义并 由于抛出异常而结束时,该异常 必须传播给调用者,如果未在那里捕获,则传播给其调用者,依此类推。
根据文档约定,本文档中指定的算法可以拦截抛出的异常,方法是指定在抛出异常时要采取的确切步骤,或者显式处理突然完成。
以下IDL 片段定义了两个接口和一个异常。
ExceptionThrower
上的 valueOf
属性被定义为在尝试获取其值时抛出异常。
[Exposed =Window ]interface Dahut {attribute DOMString type ; }; [Exposed =Window ]interface ExceptionThrower { // 此属性始终抛出 NotSupportedError 并且从不返回值。attribute long valueOf ; };
假设一个支持此接口的 JavaScript 实现, 以下代码演示了如何处理异常:
var d= getDahut(); // 获取 Dahut 的一个实例。 var et= getExceptionThrower(); // 获取 ExceptionThrower 的一个实例。 try { d. type= { toString: function () { throw "abc" ; } }; } catch ( e) { // 字符串 "abc" 在这里被捕获,因为在从原生对象转换为字符串的过程中, // 调用了匿名函数,并且 [[DefaultValue]]、ToPrimitive 或 // ToString 算法都没有定义为捕获该异常。 } try { d. type= { toString: { } }; } catch ( e) { // 这里捕获到一个异常,因为尝试在作为 toString // 属性值的原生对象上调用 [[Call]]。 } try { d. type= Symbol(); } catch ( e) { // 这里捕获到一个异常,因为尝试在 Symbol 值上调用 // JavaScript 的 ToString 抽象操作。 } d. type= et; // 这里抛出了一个未捕获的 "NotSupportedError" DOMException,因为 // [[DefaultValue]] 算法尝试获取 ExceptionThrower 对象上 // "valueOf" 属性的值。该异常会从这个代码块中传播出去。
4. 通用定义
本节规定了所有符合性实现必须支持的一些通用定义。
4.1. ArrayBufferView
typedef (Int8Array or Int16Array or Int32Array or Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or BigInt64Array or BigUint64Array or Float16Array or Float32Array or Float64Array or DataView )ArrayBufferView ;
ArrayBufferView
类型定义用于表示那些提供对 ArrayBuffer
或 SharedArrayBuffer
(当使用
[AllowShared
])进行视图的对象。
4.2. BufferSource
typedef (ArrayBufferView or ArrayBuffer )BufferSource ;
BufferSource
类型定义用于表示那些本身是 ArrayBuffer
或提供对 ArrayBuffer
视图的对象。
注意: [AllowShared
]
不能用于 BufferSource
,因为
ArrayBuffer
不支持它。应该使用 AllowSharedBufferSource
。
4.3. AllowSharedBufferSource
typedef (ArrayBuffer or SharedArrayBuffer or [AllowShared ]ArrayBufferView )AllowSharedBufferSource ;
AllowSharedBufferSource
类型定义用于表示那些本身是 ArrayBuffer
或 SharedArrayBuffer
,或者提供对
ArrayBuffer
或 SharedArrayBuffer
视图的对象。
4.4. DOMException
DOMException
类型是一个由以下 IDL 片段定义的接口类型。
[Exposed=*,Serializable ]interface DOMException { // but see below note about JavaScript bindingconstructor (optional DOMString = "",
message optional DOMString = "Error");
name readonly attribute DOMString name ;readonly attribute DOMString message ;readonly attribute unsigned short code ;const unsigned short INDEX_SIZE_ERR = 1;const unsigned short = 2;
DOMSTRING_SIZE_ERR const unsigned short HIERARCHY_REQUEST_ERR = 3;const unsigned short WRONG_DOCUMENT_ERR = 4;const unsigned short INVALID_CHARACTER_ERR = 5;const unsigned short = 6;
NO_DATA_ALLOWED_ERR const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7;const unsigned short NOT_FOUND_ERR = 8;const unsigned short NOT_SUPPORTED_ERR = 9;const unsigned short INUSE_ATTRIBUTE_ERR = 10;const unsigned short INVALID_STATE_ERR = 11;const unsigned short SYNTAX_ERR = 12;const unsigned short INVALID_MODIFICATION_ERR = 13;const unsigned short NAMESPACE_ERR = 14;const unsigned short INVALID_ACCESS_ERR = 15;const unsigned short = 16;
VALIDATION_ERR const unsigned short TYPE_MISMATCH_ERR = 17;const unsigned short SECURITY_ERR = 18;const unsigned short NETWORK_ERR = 19;const unsigned short ABORT_ERR = 20;const unsigned short URL_MISMATCH_ERR = 21;const unsigned short QUOTA_EXCEEDED_ERR = 22;const unsigned short TIMEOUT_ERR = 23;const unsigned short INVALID_NODE_TYPE_ERR = 24;const unsigned short DATA_CLONE_ERR = 25; };
注意:正如在 § 3.14.1 DOMException 自定义绑定 中讨论的那样,JavaScript 绑定对接口类型施加了超出常规要求的额外要求。
每个 DOMException
对象都有一个关联的名称和消息,
两者都是字符串。
new DOMException(message, name)
构造函数步骤如下:
code
获取器步骤是返回DOMException
名称表中为此对象的名称指示的旧版代码,如果表中不存在此类条目,则返回 0。
DOMException
对象是可序列化对象。
给定 value 和 serialized,它们的序列化步骤如下:
- 将 serialized.[[Name]] 设置为 value 的名称。
- 将 serialized.[[Message]] 设置为 value 的消息。
- 用户代理应将任何尚未指定的、值得关注的附带数据的序列化表示(特别是
stack
属性)附加到 serialized。
给定 value 和 serialized,它们的反序列化步骤如下:
- 将 value 的名称设置为 serialized.[[Name]]。
- 将 value 的消息设置为 serialized.[[Message]]。
- 如果任何其他数据附加到 serialized,则反序列化并将其附加到 value。
4.5. 函数
callback Function =any (any ...);
arguments
Function
回调函数类型用于表示没有对传递的参数或返回值类型做任何限制的函数值。
4.6. VoidFunction
callback VoidFunction =undefined ();
VoidFunction
回调函数类型用于表示不接受任何参数且不返回任何值的函数。
5. 扩展性
本节为说明性内容。
可以通过使用扩展属性来指定对语言绑定要求的扩展,这些扩展不能与本文件中定义的内容冲突。用于私有、项目特定用途的扩展不应包含在其他规范中出现的IDL 片段中。建议将需要在其他规范中使用的扩展与负责 Web IDL 工作的团队协调,该团队在撰写本文时为 W3C Web Platform 工作组,以便可能在本文件的未来版本中包含这些扩展。
强烈不建议对 IDL 语言的任何其他方面进行扩展。
6. 遗留构造
本节为说明性内容。
遗留的 Web IDL 构造仅存在于指定遗留 Web 平台特性时使用。它们通常以 "Legacy
" 字符串为前缀。除非需要指定遗留 Web
平台特性的行为,或为了与这些特性保持一致,否则强烈不建议在规范中使用遗留的 Web IDL 构造。希望使用遗留 Web IDL 构造的编辑者应在继续之前通过提交问题进行讨论。
将构造标记为遗留构造并不意味着它即将从本规范中移除。然而,它确实表明它是未来从本规范中移除的良好候选项,尤其是当各种启发式方法表明它所帮助指定的 Web 平台特性可以完全移除,或可以修改为依赖于非遗留的 Web IDL 构造时。
7. 引用本规范
本节为说明性内容。
预计其他规范在定义 Web 平台接口时,使用一个或多个IDL 片段将引用本规范。建议这些规范包括以下句子,以表明 IDL 应按照本规范的描述进行解释:
本规范附录 A 中的 IDL 片段,结合本规范规范性参考中定义的 IDL 片段,应按“Web IDL”规范中所述要求进行解释,以确保符合的 IDL 片段集。[WEBIDL]
此外,建议引用规范中的用户代理一致性类链接到本规范中的符合实现类:
符合要求的 FooML 用户代理还必须是本规范附录 A 中 IDL 片段的符合实现,如“Web IDL”规范中所述。[WEBIDL]
8. 隐私和安全注意事项
本规范定义了 JavaScript 与 IDL 值之间的转换层。不正确地实现这一层可能会导致安全问题。
本规范还通过any
和object
IDL
类型提供了直接使用 JavaScript 值的能力。这些值需要谨慎处理以避免安全问题。特别是,用户脚本可以响应对这些值的几乎任何操作运行,并使使用它们的规范或实现的预期失效。
本规范使得与SharedArrayBuffer
对象的交互成为可能,这些对象可以被用来构建时间攻击。使用这些对象的规范需要考虑此类攻击。
致谢
本节为说明性内容。
编辑们感谢以下人士为本规范做出的贡献: Glenn Adams, David Andersson, Jake Archibald, Tab Atkins-Bittner, L. David Baron, Art Barstow, Nils Barth, Robin Berjon, David Bruant, Jan-Ivar Bruaroey, Marcos Cáceres, Giovanni Campagna, François Daoust, Domenic Denicola, Chris Dumez, Michael Dyck, Daniel Ehrenberg, Brendan Eich, João Eiras, Gorm Haug Eriksen, Sigbjorn Finne, David Flanagan, Aryeh Gregor, Dimitry Golubovsky, James Graham, Aryeh Gregor, Tiancheng “Timothy” Gu, Kartikaya Gupta, Marcin Hanclik, Jed Hartman, Stefan Haustein, Dominique Hazaël-Massieux, Ian Hickson, Björn Höhrmann, Kyle Huey, Lachlan Hunt, Oliver Hunt, Jim Jewett, Wolfgang Keller, Anne van Kesteren, Olav Junker Kjær, Takayoshi Kochi, Magnus Kristiansen, Raphael Kubo da Costa, Takeshi Kurosawa, Yves Lafon, Travis Leithead, Jim Ley, Kevin Lindsey, Jens Lindström, Peter Linss, 吕康豪 (Kang-Hao Lu), Kyle Machulis, Darien Maillet Valentine, Mark Miller, Ms2ger, Andrew Oakley, 岡坂 史紀 (Shiki Okasaka), Jason Orendorff, Olli Pettay, Simon Pieters, Andrei Popescu, François Remy, Tim Renouf, Jeremy Roman, Tim Ruffles, Alex Russell, Takashi Sakamoto, Doug Schepers, Jonas Sicking, Garrett Smith, Sam Sneddon, Jungkee Song, Josh Soref, Maciej Stachowiak, Austin Sullivan, Anton Tayanovskyy, triple-underscore, Peter Van der Beken, Jeff Walden, Allen Wirfs-Brock, Jeffrey Yasskin, 以及 Collin Xu。
特别感谢 Sam Weinig 在编辑无法完成此文档期间进行维护。
本标准由 Edgar Chen (Mozilla, echen@mozilla.com) 和 Tiancheng "Timothy" Gu (timothygu99@gmail.com) 编写,Boris Zbarsky (bzbarsky@mit.edu), Cameron McCormack (cam@mcc.id.au) 以及 Tobie Langel (tobie@unlockopen.com) 也做出了重要贡献。
IDL 语法
本节定义了一个 LL(1) 语法,其起始符号
语法中的每个生成式在其右侧要么有一个非零序列的终端符号和非终端符号,要么是表示无符号的 epsilon (ε)。以大写字母开头的符号是非终端符号。以等宽字体显示的符号是终端符号。以无衬线字体显示且以小写字母开头的符号是符合正则表达式(使用 Perl 5 正则表达式语法 [PERLRE])的终端符号:
= |
/-?([1-9][0-9]*|0[Xx][0-9A-Fa-f]+|0[0-7]*)/
|
|
= |
/-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)/
|
|
= |
/[_-]?[A-Za-z][0-9A-Z_a-z-]*/
|
|
= |
/"[^"]*"/ |
|
= |
/[\t\n\r ]+/ |
|
= |
/\/\/.*|\/\*(.|\n)*?\*\//
|
|
= |
/[^\t\n\r 0-9A-Za-z]/
|
词法分析器作用于 标量值的序列。当进行词法分析时,必须使用尽可能长的匹配。例如,如果输入文本为 “a1”,则其被词法分析为一个 long
",输入文本 “.” 被词法分析为终端符号
IDL 语法对在语法中使用的等宽字体终端符号以及用于 A
" 与名为
"a
" 的标识符是不同的,一个 [legacyfactoryfunction
] 扩展属性不会被识别为 [LegacyFactoryFunction
]
扩展属性。
隐式地,在被解析的输入文本中的每个其他终端符号之间都允许有任意数量的
以下 LL(1) 语法,从
Definitions ::ExtendedAttributeList Definition Definitions εDefinition ::CallbackOrInterfaceOrMixin Namespace Partial Dictionary Enum Typedef IncludesStatement ArgumentNameKeyword ::async attribute callback const constructor deleter dictionary enum getter includes inherit interface iterable maplike mixin namespace partial readonly required setlike setter static stringifier typedef unrestricted CallbackOrInterfaceOrMixin ::callback CallbackRestOrInterface interface InterfaceOrMixin InterfaceOrMixin ::InterfaceRest MixinRest InterfaceRest ::identifier Inheritance { InterfaceMembers } ; Partial ::partial PartialDefinition PartialDefinition ::interface PartialInterfaceOrPartialMixin PartialDictionary Namespace PartialInterfaceOrPartialMixin ::PartialInterfaceRest MixinRest PartialInterfaceRest ::identifier { PartialInterfaceMembers } ; InterfaceMembers ::ExtendedAttributeList InterfaceMember InterfaceMembers εInterfaceMember ::PartialInterfaceMember Constructor PartialInterfaceMembers ::ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers εPartialInterfaceMember ::Const Operation Stringifier StaticMember Iterable AsyncIterable ReadOnlyMember ReadWriteAttribute ReadWriteMaplike ReadWriteSetlike InheritAttribute Inheritance ::: identifier εMixinRest ::mixin identifier { MixinMembers } ; MixinMembers ::ExtendedAttributeList MixinMember MixinMembers εMixinMember ::Const RegularOperation Stringifier OptionalReadOnly AttributeRest IncludesStatement ::identifier includes identifier ; CallbackRestOrInterface ::CallbackRest interface identifier { CallbackInterfaceMembers } ; CallbackInterfaceMembers ::ExtendedAttributeList CallbackInterfaceMember CallbackInterfaceMembers εCallbackInterfaceMember ::Const RegularOperation Const ::const ConstType identifier = ConstValue ; ConstValue ::BooleanLiteral FloatLiteral integer BooleanLiteral ::true false FloatLiteral ::decimal -Infinity Infinity NaN ConstType ::PrimitiveType identifier ReadOnlyMember ::readonly ReadOnlyMemberRest ReadOnlyMemberRest ::AttributeRest MaplikeRest SetlikeRest ReadWriteAttribute ::AttributeRest InheritAttribute ::inherit AttributeRest AttributeRest ::attribute TypeWithExtendedAttributes AttributeName ; AttributeName ::AttributeNameKeyword identifier AttributeNameKeyword ::async required OptionalReadOnly ::readonly εDefaultValue ::ConstValue string [ ] { } null undefined Operation ::RegularOperation SpecialOperation RegularOperation ::Type OperationRest SpecialOperation ::Special RegularOperation Special ::getter setter deleter OperationRest ::OptionalOperationName ( ArgumentList ) ; OptionalOperationName ::OperationName εOperationName ::OperationNameKeyword identifier OperationNameKeyword ::includes ArgumentList ::Argument Arguments εArguments ::, Argument Arguments εArgument ::ExtendedAttributeList ArgumentRest ArgumentRest ::optional TypeWithExtendedAttributes ArgumentName Default Type Ellipsis ArgumentName ArgumentName ::ArgumentNameKeyword identifier Ellipsis ::... εConstructor ::constructor ( ArgumentList ) ; Stringifier ::stringifier StringifierRest StringifierRest ::OptionalReadOnly AttributeRest ; StaticMember ::static StaticMemberRest StaticMemberRest ::OptionalReadOnly AttributeRest RegularOperation Iterable ::iterable < TypeWithExtendedAttributes OptionalType > ; OptionalType ::, TypeWithExtendedAttributes εAsyncIterable ::async iterable < TypeWithExtendedAttributes OptionalType > OptionalArgumentList ; OptionalArgumentList ::( ArgumentList ) εReadWriteMaplike ::MaplikeRest MaplikeRest ::maplike < TypeWithExtendedAttributes , TypeWithExtendedAttributes > ; ReadWriteSetlike ::SetlikeRest SetlikeRest ::setlike < TypeWithExtendedAttributes > ; Namespace ::namespace identifier { NamespaceMembers } ; NamespaceMembers ::ExtendedAttributeList NamespaceMember NamespaceMembers εNamespaceMember ::RegularOperation readonly AttributeRest Const Dictionary ::dictionary identifier Inheritance { DictionaryMembers } ; DictionaryMembers ::DictionaryMember DictionaryMembers εDictionaryMember ::ExtendedAttributeList DictionaryMemberRest DictionaryMemberRest ::required TypeWithExtendedAttributes identifier ; Type identifier Default ; PartialDictionary ::dictionary identifier { DictionaryMembers } ; Default ::= DefaultValue εEnum ::enum identifier { EnumValueList } ; EnumValueList ::string EnumValueListComma EnumValueListComma ::, EnumValueListString εEnumValueListString ::string EnumValueListComma εCallbackRest ::identifier = Type ( ArgumentList ) ; Typedef ::typedef TypeWithExtendedAttributes identifier ; Type ::SingleType UnionType Null TypeWithExtendedAttributes ::ExtendedAttributeList Type SingleType ::DistinguishableType any PromiseType UnionType ::( UnionMemberType or UnionMemberType UnionMemberTypes ) UnionMemberType ::ExtendedAttributeList DistinguishableType UnionType Null UnionMemberTypes ::or UnionMemberType UnionMemberTypes εDistinguishableType ::PrimitiveType Null StringType Null identifier Null sequence < TypeWithExtendedAttributes > Null async iterable < TypeWithExtendedAttributes > Null object Null symbol Null BufferRelatedType Null FrozenArray < TypeWithExtendedAttributes > Null ObservableArray < TypeWithExtendedAttributes > Null RecordType Null undefined Null PrimitiveType ::UnsignedIntegerType UnrestrictedFloatType boolean byte octet bigint UnrestrictedFloatType ::unrestricted FloatType FloatType FloatType ::float double UnsignedIntegerType ::unsigned IntegerType IntegerType IntegerType ::short long OptionalLong OptionalLong ::long εStringType ::ByteString DOMString USVString PromiseType ::Promise < Type > RecordType ::record < StringType , TypeWithExtendedAttributes > Null ::? εBufferRelatedType ::ArrayBuffer SharedArrayBuffer DataView Int8Array Int16Array Int32Array Uint8Array Uint16Array Uint32Array Uint8ClampedArray BigInt64Array BigUint64Array Float16Array Float32Array Float64Array ExtendedAttributeList ::[ ExtendedAttribute ExtendedAttributes ] εExtendedAttributes ::, ExtendedAttribute ExtendedAttributes εExtendedAttribute ::( ExtendedAttributeInner ) ExtendedAttributeRest [ ExtendedAttributeInner ] ExtendedAttributeRest { ExtendedAttributeInner } ExtendedAttributeRest Other ExtendedAttributeRest ExtendedAttributeRest ::ExtendedAttribute εExtendedAttributeInner ::( ExtendedAttributeInner ) ExtendedAttributeInner [ ExtendedAttributeInner ] ExtendedAttributeInner { ExtendedAttributeInner } ExtendedAttributeInner OtherOrComma ExtendedAttributeInner εOther ::integer decimal identifier string other - -Infinity . ... : ; < = > ? * ByteString DOMString FrozenArray Infinity NaN ObservableArray Promise USVString any bigint boolean byte double false float long null object octet or optional record sequence short symbol true unsigned undefined ArgumentNameKeyword BufferRelatedType OtherOrComma ::Other , IdentifierList ::identifier Identifiers Identifiers ::, identifier Identifiers εExtendedAttributeNoArgs ::identifier ExtendedAttributeArgList ::identifier ( ArgumentList ) ExtendedAttributeIdent ::identifier = identifier ExtendedAttributeWildcard ::identifier = * ExtendedAttributeIdentList ::identifier = ( IdentifierList ) ExtendedAttributeNamedArgList ::identifier = identifier ( ArgumentList )
注意:
虽然
文档约定
本文档中使用了以下排版约定:
-
术语定义实例:示例术语
-
指向本文档或其他地方定义的术语的链接:示例术语
-
语法终端符:
sometoken -
语法非终端符:
ExampleGrammarNonTerminal -
语法符号:
identifier -
IDL 类型:
unsigned long
-
JavaScript 类:
Map
-
JavaScript 语言类型:Object
-
代码片段:
a = b + obj.f()
-
标量值:U+0030 (0)
-
扩展属性:[
ExampleExtendedAttribute
] -
文章和算法中的变量名:exampleVariableName。
-
IDL 非正式语法示例:
[
extended_attributes ]interface identifier { /* interface_members... */ };(语法中的具体部分在周围的文章中讨论,并用 高亮 标出。)
-
IDL 语法片段:
ExampleGrammarNonTerminal ::OtherNonTerminal sometoken other AnotherNonTerminal ε //nothing -
非规范性注释:
注意: 这是一个注释。
-
非规范性示例:
-
规范性警告:
这是一个警告。
-
代码块:
// 这是一个 IDL 代码块。 [
Exposed =Window ]interface Example {attribute long something ; };// 这是一个 JavaScript 代码块。 window. onload= function () { window. alert( "loaded" ); };
本文档中的算法使用了以下约定:
-
算法有时会将返回值/抛出值与返回完成记录互换处理。 也就是说,使用返回/抛出术语的算法可能被视为返回一个完成记录,而返回完成记录的算法可能被视为返回一个值或抛出一个异常。类似地,为了捕获异常,定义抛出异常时要采取的行为与检查完成记录的 [[Type]] 字段是否为 “throw” 是等效的。
-
完成记录通过允许它们包含非 JavaScript 值(例如 Web IDL 值)而得到扩展。
一致性
本规范中的所有内容均为规范性,除图表、示例、注释和标注为信息性部分的章节外。
本规范依赖于 Infra 标准。[INFRA]
本规范定义了以下一致性类别:
- 符合要求的 IDL 片段集合
-
当一组 IDL 片段 共同满足本规范中对 IDL 片段适用的所有必须、必需和应级别的标准时,认为其为 符合要求的 IDL 片段集合。
- 符合要求的实现
-
当用户代理相对于 符合要求的 IDL 片段集合,满足本规范中对用户代理所支持的所有语言绑定的实现适用的所有必须、必需和应级别的标准时,认为其为 符合要求的实现。
- 一致的 JavaScript 实现
-
当用户代理相对于 符合要求的 IDL 片段集合,满足本规范中对 JavaScript 语言绑定的实现适用的所有必须、必需和应级别的标准时,认为其为 符合要求的 JavaScript 实现。
知识产权
版权 © WHATWG(Apple、Google、Mozilla、Microsoft)。本作品根据 知识共享署名 4.0 国际许可协议 许可。若将本标准的部分内容并入源代码中,这些部分在源代码中将根据 BSD 3-Clause License 许可。
这是现行标准。有兴趣查看专利审核版本的人应参阅 现行标准审核草案。