1. Introduction
This section is informative.
This standard defines an interface definition language, Web IDL, that can be used to describe interfaces that are intended to be implemented in web browsers. Web IDL is an IDL variant with a number of features that allow the behavior of common script objects in the web platform to be specified more readily. How interfaces described with Web IDL correspond to constructs within JavaScript execution environments is also detailed here.
Concretely, Web IDL provides a syntax for specifying the surface APIs of web platform objects, as well as JavaScript bindings that detail how those APIs manifest as JavaScript constructs. This ensures common tasks, such as installing global properties, processing numeric inputs, or exposing iteration behavior, remain uniform across web platform specifications: such specifications describe their interfaces using Web IDL, and then use prose to specify API-specific details.
The term "JavaScript" is used to refer to ECMA-262, rather than the official term ECMAScript, since the term JavaScript is more widely known.
2. Interface definition language
This section describes a language, Web IDL, which can be used to define
interfaces for APIs in the Web platform. A specification that defines Web APIs
can include one or more IDL fragments that
describe the interfaces (the state and behavior that objects can exhibit)
for the APIs defined by that specification.
An IDL fragment is
a sequence of definitions that matches the
The different kinds of definitions that can appear in an IDL fragment are: interfaces, partial interface definitions, interface mixins, partial mixin definitions, callback functions, callback interfaces, namespaces, partial namespace definitions, dictionaries, partial dictionary definitions, typedefs and includes statements. These are all defined in the following sections.
Each definition (matching
[extended_attributes ]interface identifier { /* interface_members... */ };
Definitions ::ExtendedAttributeList Definition Definitions ε
Definition ::CallbackOrInterfaceOrMixin Namespace Partial Dictionary Enum Typedef IncludesStatement
The following is an example of an IDL fragment.
[Exposed =Window ]interface Paint { }; [Exposed =Window ]interface SolidColor :Paint {attribute double red ;attribute double green ;attribute double blue ; }; [Exposed =Window ]interface Pattern :Paint {attribute DOMString imageURL ; }; [Exposed =Window ]interface GraphicalWindow {constructor ();readonly attribute unsigned long width ;readonly attribute unsigned long height ;attribute Paint currentPaint ;undefined drawRectangle (double x ,double y ,double width ,double height );undefined drawText (double x ,double y ,DOMString text ); };
Here, four interfaces are being defined.
The GraphicalWindow
interface has two read only attributes,
one writable attribute, and two operations defined on it. Objects that implement the GraphicalWindow
interface
will expose these attributes and operations in a manner appropriate to the
particular language being used.
In JavaScript, the attributes on the IDL interfaces will be exposed as accessor
properties and the operations as data properties whose value is a built-in function object on a
prototype object for all GraphicalWindow
objects; each JavaScript object that implements GraphicalWindow
will have that prototype object in its prototype chain.
The constructor operation that appears on GraphicalWindow
causes a constructor to exist in JavaScript implementations,
so that calling new GraphicalWindow()
would return a new object
that implemented the interface.
All interfaces have the [Exposed
] extended attribute, which ensures the interfaces
are only available in realms whose global object is a Window
object.
2.1. Names
Every interface, partial interface definition, namespace, partial namespace definition, dictionary, partial dictionary definition, enumeration, callback function, callback interface and typedef (together called named definitions)
and every constant, attribute,
and dictionary member has an identifier, as do some operations.
The identifier is determined by an
-
For named definitions, the
identifier token that appears directly after theinterface ,namespace ,dictionary ,enum orcallback keyword determines the identifier of that definition.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... */ }; -
For attributes, typedefs and dictionary members, the final
identifier token before the semicolon at the end of the declaration determines the identifier.[
extended_attributes ]interface identifier {attribute type attribute_identifier ; };typedef type typedef_identifier ;dictionary identifier {type dictionary_member_identifier ; }; -
For constants, the
identifier token before the equals sign determines the identifier.const type constant_identifier = 42; -
For operations, the
identifier token that appears after the return type but before the opening parenthesis (that is, one that is matched as part of theOptionalOperationName grammar symbol in anOperationRest ) determines the identifier of the operation. If there is no suchidentifier token, then the operation does not have an identifier.interface interface_identifier {return_type operation_identifier (/* arguments... */); };
Note: Operations can have no identifier when they are being used to declare a special kind of operation, such as a getter or setter.
For all of these constructs, the identifier is the value of the
Note: A leading U+005F (_) is used to escape an identifier from looking
like a reserved word so that, for example, an interface named "interface
" can be
defined. The leading U+005F (_) is dropped to unescape the
identifier.
Operation arguments can take a slightly wider set of identifiers. In an operation
declaration, the identifier of an argument is specified immediately after its
type and is given by either an
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
If an
The identifier of any of the abovementioned
IDL constructs (except operation arguments) must not be "constructor
",
"toString
",
or begin with a U+005F (_). These
are known as reserved identifiers.
Although the "toJSON
" identifier is not a reserved identifier,
it must only be used for regular operations that convert objects to JSON types,
as described in § 2.5.3.1 toJSON.
Note: Further restrictions on identifier names for particular constructs can be made in later sections.
Within the set of IDL fragments that a given implementation supports, the identifier of every interface, namespace, dictionary, enumeration, callback function, callback interface and typedef must not be the same as the identifier of any other interface, namespace, dictionary, enumeration, callback function, callback interface or typedef.
Within an IDL fragment, a reference to a definition need not appear after the declaration of the referenced definition. References can also be made across IDL fragments.
Therefore, the following IDL fragment is valid:
[Exposed =Window ]interface B :A {undefined f (SequenceOfLongs x ); }; [Exposed =Window ]interface A { };typedef sequence <long >SequenceOfLongs ;
The following IDL fragment demonstrates how identifiers are given to definitions and interface members.
// 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 ; };
Note that while the second attribute on the TextField
interface need not have been escaped with an underscore (because "value
" is
not a keyword in the IDL grammar), it is still unescaped
to obtain the attribute’s identifier.
2.2. Interfaces
IDL fragments are used to
describe object oriented systems. In such systems, objects are entities
that have identity and which are encapsulations of state and behavior.
An interface is a definition (matching
[extended_attributes ]interface identifier { /* interface_members... */ };
An interface is a specification of a set of interface members (matching
Interfaces in Web IDL describe how objects that implement the interface behave. In bindings for object oriented languages, it is expected that an object that implements a particular IDL interface provides ways to inspect and modify the object’s state and to invoke the behavior described by the interface.
An interface can be defined to inherit from another interface. If the identifier of the interface is followed by a U+003A (:) and an identifier, then that identifier identifies the inherited interface. An object that implements an interface that inherits from another also implements that inherited interface. The object therefore will also have members that correspond to the interface members from the inherited interface.
interface identifier :identifier_of_inherited_interface { /* interface_members... */ };
The order that members appear in has significance for property enumeration in the JavaScript binding.
Interfaces may specify an interface member that has the same name as one from an inherited interface. Objects that implement the derived interface will expose the member on the derived interface. It is language binding specific whether the overridden member can be accessed on the object.
Consider the following two interfaces.
[Exposed =Window ]interface A {undefined f ();undefined g (); }; [Exposed =Window ]interface B :A {undefined f ();undefined g (DOMString x ); };
In the JavaScript language binding, an instance of B
will have a prototype chain that looks like the following:
[Object.prototype: the Object prototype object] ↑ [A.prototype: interface prototype object for A] ↑ [B.prototype: interface prototype object for B] ↑ [instanceOfB]
Calling instanceOfB.f()
in JavaScript will invoke the f defined
on B
. However, the f from A
can still be invoked on an object that implements B
by
calling A.prototype.f.call(instanceOfB)
.
The inherited interfaces of a given interface A is the set of all interfaces that A inherits from, directly or indirectly. If A does not inherit from another interface, then the set is empty. Otherwise, the set includes the interface B that A inherits from and all of B’s inherited interfaces.
An interface must not be declared such that its inheritance hierarchy has a cycle. That is, an interface A cannot inherit from itself, nor can it inherit from another interface B that inherits from A, and so on.
Note that general multiple inheritance of interfaces is not supported, and objects also cannot implement arbitrary sets of interfaces. Objects can be defined to implement a single given interface A, which means that it also implements all of A’s inherited interfaces. In addition, an includes statement can be used to define that objects implementing an interface A will always also include the members of the interface mixins A includes.
Each interface member can be preceded by a list of extended attributes (matching
[extended_attributes ]interface identifier { [extended_attributes ]const type constant_identifier = 42; [extended_attributes ]attribute type identifier ; [extended_attributes ]return_type identifier (/* arguments... */); };
The IDL for interfaces can be split into multiple parts by using partial interface definitions
(matching
interface SomeInterface { /* interface_members... */ };partial interface SomeInterface { /* interface_members... */ };
Note: Partial interface definitions are intended for use as a specification editorial aide, allowing the definition of an interface to be separated over more than one section of the document, and sometimes multiple documents.
The order of appearance of an interface definition and any of its partial interface definitions does not matter.
Note: A partial interface definition cannot specify that the interface inherits from another interface. Inheritance is to be specified on the original interface definition.
The relevant language binding determines how interfaces correspond to constructs in the language.
The following extended attributes are applicable to interfaces:
[CrossOriginIsolated
],
[Exposed
],
[Global
],
[LegacyFactoryFunction
],
[LegacyNoInterfaceObject
],
[LegacyOverrideBuiltIns
],
[LegacyWindowAlias
], and
[SecureContext
].
The following extended attributes are applicable to partial interfaces:
[CrossOriginIsolated
],
[Exposed
],
[LegacyOverrideBuiltIns
], and
[SecureContext
].
Interfaces must be annotated with an [Exposed
] extended attribute.
The qualified name of an interface interface is defined as follows:
-
Let identifier be the identifier of interface.
-
If interface has a [
LegacyNamespace
] extended attribute, then:-
Let namespace be the identifier argument of the [
LegacyNamespace
] extended attribute. -
Return the concatenation of « namespace, identifier » with separator U+002E (.).
-
-
Return 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 ε
The following IDL fragment demonstrates the definition of two mutually referential interfaces.
Both Human
and Dog
inherit from Animal
. Objects that implement
either of those two interfaces will thus have a name
attribute.
[Exposed =Window ]interface Animal {attribute DOMString name ; }; [Exposed =Window ]interface Human :Animal {attribute Dog ?pet ; }; [Exposed =Window ]interface Dog :Animal {attribute Human ?owner ; };
The following IDL fragment defines simplified versions of a DOM interfaces and a callback interface.
[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 ); };
Plain objects can implement a callback interface like EventListener
:
var node= getNode(); // Obtain an instance of Node. var listener= { handleEvent: function ( event) { // ... } }; node. addEventListener( "click" , listener); // This works. node. addEventListener( "click" , function () { ... }); // As does this.
It is not possible for such an object to implement an interface like Node
, however:
var node= getNode(); // Obtain an instance of Node. var newNode= { nodeName: "span" , parentNode: null , appendChild: function ( newchild) { // ... }, addEventListener: function ( type, listener) { // ... } }; node. appendChild( newNode); // This will throw a TypeError exception.
2.3. Interface mixins
An interface mixin is a definition (matching
interface mixin identifier { /* mixin_members... */ };
Note: Interface mixins, much like partial interfaces, are intended for use as a specification editorial aide, allowing a coherent set of functionalities to be grouped together, and included in multiple interfaces, possibly across documents. They are not meant to be exposed through language bindings. Guidance on when to choose partial interfaces, interface mixins, or partial interface mixins can be found in § 2.3.1 Using mixins and partials.
An interface mixin is a specification of a set of interface mixin members (matching
These constants, regular operations, regular attributes, and stringifiers describe the behaviors that can be implemented by an object, as if they were specified on the interface that includes them.
Static attributes, static operations, special operations, and iterable, asynchronously iterable, maplike, and setlike declarations cannot appear in interface mixin declarations.
As with interfaces, the IDL for interface mixins can be split into multiple parts by using partial interface mixin definitions
(matching
interface mixin SomeMixin { /* mixin_members... */ };partial interface mixin SomeMixin { /* mixin_members... */ };
The order that members appear in has significance for property enumeration in the JavaScript binding.
Note that unlike interfaces or dictionaries, interface mixins do not create types.
Of the extended attributes defined in this specification,
only the [CrossOriginIsolated
], [Exposed
], and [SecureContext
] extended attributes
are applicable to interface mixins.
An includes statement is a definition
(matching
interface_identifier includes mixin_identifier ;
The first identifier must reference a interface I. The second identifier must reference an interface mixin M.
Each member of M is considered to be a member of each interface I, J, K, … that includes M, as if a copy of each member had been made. So for a given member m of M, interface I is considered to have a member mI, interface J is considered to have a member mJ, interface K is considered to have a member mK, and so on. The host interfaces of mI, mJ, and mK, are I, J, and K respectively.
Note: In JavaScript, this implies that each regular operation declared as a member of interface mixin M, and exposed as a data property with a built-in function object value, is a distinct built-in function object in each interface prototype object whose associated interface includes M. Similarly, for attributes, each copy of the accessor property has distinct built-in function objects for its getters and setters.
The order of appearance of includes statements affects the order in which interface mixin are included by their host interface.
Member order isn’t clearly specified, in particular when interface mixins are defined in separate documents. It is discussed in issue #432.
No extended attributes defined in this specification are applicable to includes statements.
The following IDL fragment defines an interface, Entry
,
and an interface mixin, Observable
.
The includes statement specifies that Observable
’s members are always included on objects implementing Entry
.
interface Entry {readonly attribute unsigned short entryType ; // ... };interface mixin Observable {undefined addEventListener (DOMString type ,EventListener listener ,boolean useCapture ); // ... };Entry includes Observable ;
A JavaScript implementation would thus have an addEventListener
property in the prototype chain of every Entry
:
var e= getEntry(); // Obtain an instance of Entry. typeof e. addEventListener; // Evaluates to "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. Using mixins and partials
This section is informative.
Interface mixins allow the sharing of attributes, constants, and operations across multiple interfaces. If you’re only planning to extend a single interface, you might consider using a partial interface instead.
For example, instead of:
interface mixin WindowSessionStorage {readonly attribute Storage sessionStorage ; };Window includes WindowSessionStorage ;
do:
partial interface Window {readonly attribute Storage sessionStorage ; };
Additionally, you can rely on extending interface mixins exposed by other specifications to target common use cases, such as exposing a set of attributes, constants, or operations across both window and worker contexts.
For example, instead of the common but verbose:
interface mixin GlobalCrypto {readonly attribute Crypto crypto ; };Window includes GlobalCrypto ;WorkerGlobalScope includes GlobalCrypto ;
you can extend the WindowOrWorkerGlobalScope
interface mixin using a partial interface mixin:
partial interface mixin WindowOrWorkerGlobalScope {readonly attribute Crypto crypto ; };
2.4. Callback interfaces
A callback interface is a definition matching
Note: A callback interface is not an interface. The name and syntax are left over from earlier versions of this standard, where these concepts had more in common.
A callback interface is a specification of a set of callback interface members (matching
callback interface identifier { /* interface_members... */ };
Note: See also the similarly named callback function definition.
Callback interfaces must define exactly one regular operation.
Specification authors should not define callback interfaces unless required to describe the requirements of existing APIs. Instead, a callback function should be used.
The definition of EventListener
as a callback interface is an example of an existing API that needs to allow
objects with a
given property (in this case handleEvent
) to be considered to implement the interface.
For new APIs, and those for which there are no compatibility concerns,
using a callback function will allow
only a function object (in the JavaScript
language binding).
Callback interfaces which declare constants must be annotated with an [Exposed
] extended attribute.
CallbackRestOrInterface ::CallbackRest interface identifier { CallbackInterfaceMembers } ;
CallbackInterfaceMembers ::ExtendedAttributeList CallbackInterfaceMember CallbackInterfaceMembers ε
CallbackInterfaceMember ::Const RegularOperation
2.5. Members
Interfaces, interface mixins, and namespaces are specifications of a set of members (respectively matching
When an interface includes an interface mixin, each member of the interface mixin is also considered a member of the interface. In contrast, inherited interface members are not considered members of the interface.
The constructor steps, getter steps, setter steps, and method steps for the various members defined on an interface or interface mixin have access to a this value, which is an IDL value of the interface type that the member is declared on or that includes the interface mixin the member is declared on.
Setter steps also have access to the given value, which is an IDL value of the type the attribute is declared as.
Interfaces, interface mixins, callback interfaces and namespaces each support a different set of members, which are specified in § 2.2 Interfaces, § 2.3 Interface mixins, § 2.4 Callback interfaces, and § 2.6 Namespaces, and summarized in the following informative table:
2.5.1. Constants
A constant is a declaration (matching
Constants have in the past primarily been used to define named integer codes in the style of an enumeration. The Web platform is moving away from this design pattern in favor of the use of strings. Editors who wish to use this feature are strongly advised to discuss this by filing an issue before proceeding.
const type constant_identifier = 42;
The identifier of a constant must not be the same as the identifier
of another interface member or callback interface member defined on the same interface or callback interface.
The identifier also must not
be "length
", "name
" or "prototype
".
Note: These three names are the names of properties that are defined on the interface object in the JavaScript language binding.
The type of a constant (matching
The
Note: These values – in addition to strings and the empty sequence – can also be used to specify the default value of a dictionary member or of an optional argument.
Note that strings, the
empty sequence
The value of the boolean literal tokens boolean
values true
and false
.
The value of an
-
Let S be the sequence of scalar values matched by the
integer token. -
Let sign be −1 if S begins with U+002D (-), and 1 otherwise.
-
Let base be the base of the number based on the scalar values that follow the optional leading U+002D (-):
- U+0030 (0), U+0058 (X)
- U+0030 (0), U+0078 (x)
-
The base is 16.
- U+0030 (0)
-
The base is 8.
- Otherwise
-
The base is 10.
-
Let number be the result of interpreting all remaining scalar values following the optional leading U+002D (-) character and any scalar values indicating the base as an integer specified in base base.
-
Return sign × number.
The type of an
-
Let S be the sequence of scalar values matched by the
decimal token. -
Let result be the Mathematical Value that would be obtained if S were parsed as a JavaScript
NumericLiteral . -
If the
decimal token is being used as the value for afloat
orunrestricted float
, then the value of thedecimal token is the IEEE 754 single-precision floating point number closest to result. -
Otherwise, the
decimal token is being used as the value for adouble
orunrestricted double
, and the value of thedecimal token is the IEEE 754 double-precision floating point number closest to result. [IEEE-754]
The value of a constant value specified as
- Type
unrestricted float
, constant valueInfinity -
The value is the IEEE 754 single-precision positive infinity value.
- Type
unrestricted double
, constant valueInfinity -
The value is the IEEE 754 double-precision positive infinity value.
- Type
unrestricted float
, constant value-Infinity -
The value is the IEEE 754 single-precision negative infinity value.
- Type
unrestricted double
, constant value-Infinity -
The value is the IEEE 754 double-precision negative infinity value.
- Type
unrestricted float
, constant valueNaN -
The value is the IEEE 754 single-precision NaN value with the bit pattern 0x7fc00000.
- Type
unrestricted double
, constant valueNaN -
The value is the IEEE 754 double-precision NaN value with the bit pattern 0x7ff8000000000000.
The type of a float
or double
.
The value of the
If VT is the type of the value assigned to a constant, and DT is the type of the constant, dictionary member or optional argument itself, then these types must be compatible, which is the case if DT and VT are identical, or DT is a nullable type whose inner type is VT.
Constants are not associated with particular instances of the interface or callback interface on which they appear. It is language binding specific whether constants are exposed on instances.
The JavaScript language binding does however allow constants to be accessed through objects implementing the IDL interfaces on which the constants are declared. For example, with the following IDL:
[Exposed =Window ]interface A {const short rambaldi = 47; };
the constant value can be accessed in JavaScript either as A.rambaldi
or instanceOfA.rambaldi
.
The following extended attributes are applicable to constants:
[CrossOriginIsolated
],
[Exposed
], and
[SecureContext
].
Const ::const ConstType identifier = ConstValue ;
ConstValue ::BooleanLiteral FloatLiteral integer
BooleanLiteral ::true false
FloatLiteral ::decimal -Infinity Infinity NaN
ConstType ::PrimitiveType identifier
The following IDL fragment demonstrates how constants of the above types can be defined.
[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. Attributes
An attribute is an interface member or namespace member (matching
-
regular attributes, which are those used to declare that objects implementing the interface will have a data field member with the given identifier
interface interface_identifier {attribute type identifier ; }; -
static attributes, which are used to declare attributes that are not associated with a particular object implementing the interface
interface interface_identifier {static attribute type identifier ; };
If an attribute has no
The getter steps of an attribute attr should be introduced using text of the form “The attr
getter steps are:” followed by a list, or “The attr
getter steps
are to” followed by an inline description.
The setter steps of an attribute attr should be introduced using text of the form “The attr
setter steps are:” followed by a list, or “The attr
setter steps
are to” followed by an inline description.
Note: When defining getter steps, you implicitly have access to this. When defining setter steps, you implicitly have access to this and the given value.
The identifier of an attribute must not be the same as the identifier
of another interface member defined on the same interface.
The identifier of a static attribute must not
be "prototype
".
The type of the attribute is given by the type (matching
The type of the attribute, after resolving typedefs, must not be a nullable or non-nullable version of any of the following types:
-
a union type that has a nullable or non-nullable sequence type, dictionary, or record as one of its flattened member types
The attribute is read only if the
interface interface_identifier {readonly attribute type identifier ; };
Attributes whose type is a promise type must be read only. Additionally, they cannot have
any of the extended attributes [LegacyLenientSetter
], [PutForwards
], [Replaceable
], or
[SameObject
].
A regular attribute that is not read only can be declared to inherit its getter from an ancestor interface. This can be used to make a read only attribute
in an ancestor interface be writable on a derived interface. An attribute inherits its getter if
its declaration includes
Note: The grammar ensures that
[Exposed =Window ]interface Ancestor {readonly attribute TheType theIdentifier ; }; [Exposed =Window ]interface Derived :Ancestor {inherit attribute TheType theIdentifier ; };
When the
interface interface_identifier {stringifier attribute DOMString identifier ; };
The following extended attributes are applicable to regular and static attributes:
[CrossOriginIsolated
],
[Exposed
],
[SameObject
], and
[SecureContext
].
The following extended attributes are applicable only to regular attributes:
[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 ε
The following IDL fragment demonstrates how attributes can be declared on an interface:
[Exposed =Window ]interface Animal { // A simple attribute that can be set to any string value.readonly attribute DOMString name ; // An attribute whose value can be assigned to.attribute unsigned short age ; }; [Exposed =Window ]interface Person :Animal { // An attribute whose getter behavior is inherited from Animal, and need not be // specified in the description of Person.inherit attribute DOMString name ; };
2.5.3. Operations
An operation is an interface member, callback interface
member or namespace member (matching
-
regular operations, which are those used to declare that objects implementing the interface will have a method with the given identifier
interface interface_identifier {return_type identifier (/* arguments... */); }; -
special operations, which are used to declare special behavior on objects implementing the interface, such as object indexing and stringification
interface interface_identifier { /* special_keyword */return_type identifier (/* arguments... */); /* special_keyword */return_type (/* arguments... */); }; -
static operations, which are used to declare operations that are not associated with a particular object implementing the interface
interface interface_identifier {static return_type identifier (/* arguments... */); };
If an operation has an identifier but no
If an operation has no identifier, then it must be declared to be a special operation using one of the special keywords.
The identifier of a regular operation or static operation must not be the same as the identifier
of a constant or attribute defined on the same interface, callback interface or namespace.
The identifier of a static operation must not be "prototype
".
Note: The identifier can be the same as that of another operation on the interface, however. This is how operation overloading is specified.
Note: The identifier of a static operation can be the same as the identifier of a regular operation defined on the same interface.
The return type of the operation is given
by the type (matching
An operation’s arguments (matching
Note: For expressiveness, the identifier of an operation argument can also be specified
as one of the keywords matching the
If the
If the operation argument type, after resolving typedefs, is a nullable type, its inner type must not be a dictionary type.
interface interface_identifier {return_type identifier (type identifier ,type identifier /* , ... */); };
The identifier of each argument must not be the same as the identifier of another argument in the same operation declaration.
Each argument can be preceded by a list of extended attributes (matching
interface interface_identifier {return_type identifier ([extended_attributes ]type identifier , [extended_attributes ]type identifier /* , ... */); };
The following IDL fragment demonstrates how regular operations can be declared on an interface:
[Exposed =Window ]interface Dimensions {attribute unsigned long width ;attribute unsigned long height ; }; [Exposed =Window ]interface Button { // An operation that takes no arguments and returns a boolean.boolean isMouseOver (); // Overloaded operations.undefined setDimensions (Dimensions size );undefined setDimensions (unsigned long width ,unsigned long height ); };
An operation or constructor operation is considered to be variadic if the final argument uses the
interface interface_identifier {return_type identifier (type ...identifier );return_type identifier (type identifier ,type ...identifier ); };
Extended attributes that take an argument list ([LegacyFactoryFunction
], of those
defined in this specification) and callback functions are also considered to be variadic when the
The following IDL fragment defines an interface that has two variadic operations:
[Exposed =Window ]interface IntegerSet {readonly attribute unsigned long cardinality ;undefined union (long ...ints );undefined intersection (long ...ints ); };
In the JavaScript binding, variadic operations are implemented by functions that can accept the subsequent arguments:
var s= getIntegerSet(); // Obtain an instance of IntegerSet. s. union(); // Passing no arguments corresponding to 'ints'. s. union( 1 , 4 , 7 ); // Passing three arguments corresponding to 'ints'.
A binding for a language that does not support variadic functions might specify that an explicit array or list of integers be passed to such an operation.
An argument is considered to be an optional argument if it is declared with the
interface interface_identifier {return_type identifier (type identifier ,optional type identifier ); };
Optional arguments can also have a default value specified. If the argument’s identifier is followed by a U+003D (=)
and a value (matching
interface interface_identifier {return_type identifier (type identifier ,optional type identifier = "value"); };
It is strongly suggested not to use a default value of boolean
-typed arguments,
as this can be confusing for authors who might otherwise expect the default
conversion of
If the type of an argument is a dictionary type or a union type that has a dictionary type as one of its flattened member types, and that dictionary type and its ancestors have no required members, and the argument is either the final argument or is followed only by optional arguments, then the argument must be specified as optional and have a default value provided.
This is to encourage API designs that do not require authors to pass an empty dictionary value when they wish only to use the dictionary’s default values.
Usually the default value provided will be
When a boolean literal token (
When the undefined
value.
-
Let S be the sequence of scalar values matched by the
string token with its leading and trailing U+0022 (") scalar values removed. -
Depending on the type of the argument:
DOMString
USVString
- an enumeration type
-
The value of the
string token is S. ByteString
-
Assert: S doesn’t contain any code points higher than U+00FF.
The value of the
string token is the isomorphic encoding of S.
If the type of the optional argument is an enumeration, then its default value if specified must be one of the enumeration’s values.
Optional argument default values can also be specified using the
two token value
Optional argument default values can also be specified using the two token value
The following IDL fragment defines an interface with a single operation that can be invoked with two different argument list lengths:
[Exposed =Window ]interface ColorCreator {object createColor (double v1 ,double v2 ,double v3 ,optional double alpha ); };
It is equivalent to an interface that has two overloaded operations:
[Exposed =Window ]interface ColorCreator {object createColor (double v1 ,double v2 ,double v3 );object createColor (double v1 ,double v2 ,double v3 ,double alpha ); };
The following IDL fragment defines an interface with an operation that takes a dictionary argument:
dictionary LookupOptions {boolean caseSensitive =false ; }; [Exposed =Window ]interface AddressBook {boolean hasAddressForName (USVString name ,optional LookupOptions options = {}); };
If hasAddressForName
is called with only one argument, the
second argument will be a default-initialized LookupOptions
dictionary, which will cause caseSensitive
to be set to
The following extended attributes are applicable to operations:
[CrossOriginIsolated
],
[Default
],
[Exposed
],
[LegacyUnforgeable
],
[NewObject
], and
[SecureContext
].
The method steps of an operation operation should be introduced using text of the form
“The operation(arg1, arg2, ...)
method
steps are:” followed by a list, or “The operation(arg1, arg2, ...)
method steps are to” followed by an inline description.
Note: When defining method steps, you implicitly have access to this.
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
By declaring a toJSON
regular operation,
an interface specifies how to convert the objects that implement it to JSON types.
The toJSON
regular operation is reserved for this usage.
It must take zero arguments and return a JSON type.
The JSON types are:
-
nullable types whose inner type is a JSON type,
-
annotated types whose inner type is a JSON type,
-
union types whose member types are JSON types,
-
typedefs whose type being given a new name is a JSON type,
-
sequence types whose parameterized type is a JSON type,
-
frozen array types whose parameterized type is a JSON type,
-
dictionary types where the types of all members declared on the dictionary and all its inherited dictionaries are JSON types,
-
records where all of their values are JSON types,
-
interface types that have a
toJSON
operation declared on themselves or one of their inherited interfaces.
How the toJSON
regular operation is made available on an object in a language binding,
and how exactly the JSON types are converted into a JSON string,
is language binding specific.
Note: In the JavaScript language binding,
this is done by exposing a toJSON
method
which returns the JSON type converted into a JavaScript value
that can be turned into a JSON string
by the JSON.stringify()
function.
Additionally, in the JavaScript language binding,
the toJSON
operation can take a [Default
] extended attribute,
in which case the default toJSON steps are exposed instead.
The following IDL fragment defines an interface Transaction
that has a toJSON
method defined in prose:
[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 ; };
The toJSON
regular operation of Transaction
interface could be defined as follows:
The toJSON()
method steps are:
-
Let json be a new map.
-
For each attribute identifier attr in « "from", "to", "amount", "description" »:
-
Let value be the result of running the getter steps of attr on this.
-
Set json[attr] to value.
-
-
Return json.
In the JavaScript language binding, there would exist a toJSON()
method on Transaction
objects:
// Get an instance of Transaction. var txn= getTransaction(); // Evaluates to an object like this: // { // from: "Bob", // to: "Alice", // amount: 50, // description: "books" // } txn. toJSON(); // Evaluates to a string like this: // '{"from":"Bob","to":"Alice","amount":50,"description":"books"}' JSON. stringify( txn);
2.5.4. Constructor operations
If an interface has a constructor operation member (matching
Multiple constructor operations may appear on a given interface. For each constructor operation on the interface, there will be a way to attempt to construct an instance by passing the specified arguments.
The constructor steps of a constructor operation that is a member of an interface
named interface should be introduced using text of the form “The new interface(arg1, arg2, ...)
constructor steps
are:” followed by a list, or “The new interface(arg1, arg2, ...)
constructor steps
are to” followed by an inline description.
The constructor steps must do nothing, initialize the value passed as this, or throw an exception.
If the constructor does not initialize this, one can write “The new Example(init)
constructor
steps are to do nothing.”
See § 3.7.1 Interface object for details on how a constructor operation is to be implemented.
The following IDL defines two interfaces. The second has constructor operations, while the first does not.
[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 ; };
A JavaScript implementation supporting these interfaces would implement a [[Construct]]
internal method on the Circle
interface object which would return a
new object that implements the interface.
It would take either zero or one argument.
It is unclear whether the NodeList
interface
object would implement a [[Construct]] internal method. In any case, trying to use it as a
constructor will cause a TypeError
to be thrown.
var x= new Circle(); // This uses the zero-argument constructor to create a // reference to a platform object that implements the // Circle interface. var y= new Circle( 1.25 ); // This also creates a Circle object, this time using // the one-argument constructor. var z= new NodeList(); // This would throw a TypeError, since no // constructor is declared.
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. Stringifiers
When an interface has a stringifier, it indicates that objects
that implement the interface have a non-default conversion to a string. Stringifiers can be
specified using a
interface interface_identifier {stringifier ; };
Prose accompanying the interface must define the stringification behavior of the interface.
The DOMString
or USVString
.
It also must not be placed on
a static attribute.
interface interface_identifier {stringifier attribute DOMString identifier ; };
On a given interface, there must exist at most one stringifier.
Stringifier ::stringifier StringifierRest
StringifierRest ::OptionalReadOnly AttributeRest ;
The following IDL fragment defines an interface that will stringify to the value of its name
attribute:
[Exposed =Window ]interface Student {constructor ();attribute unsigned long id ;stringifier attribute DOMString name ; };
In the JavaScript binding, using a Student
object in a context where a string is expected will result in the
value of the object’s name
property being
used:
var s= new Student(); s. id= 12345678 ; s. name= '周杰倫' ; var greeting= 'Hello, ' + s+ '!' ; // Now greeting == 'Hello, 周杰倫!'.
The following IDL fragment defines an interface that has custom stringification behavior that is not specified in the IDL itself.
[Exposed =Window ]interface Student {constructor ();attribute unsigned long id ;attribute DOMString ?familyName ;attribute DOMString givenName ;stringifier ; };
Thus, there needs to be prose to explain the stringification behavior.
We assume that the familyName
and givenName
attributes are backed by
family name and given name concepts, respectively.
The stringification behavior steps are:
A JavaScript implementation of the IDL would behave as follows:
var s= new Student(); s. id= 12345679 ; s. familyName= 'Smithee' ; s. givenName= 'Alan' ; var greeting= 'Hi ' + s; // Now greeting == 'Hi Alan Smithee'.
2.5.6. Special operations
A special operation is a declaration of a certain kind of special behavior on objects implementing the interface on which the special operation declarations appear. Special operations are declared by using a special keyword in an operation declaration.
There are three kinds of special operations. The table below indicates for a given kind of special operation what special keyword is used to declare it and what the purpose of the special operation is:
Special operation | Keyword | Purpose |
---|---|---|
Getters | Defines behavior for when an object is indexed for property retrieval. | |
Setters | Defines behavior for when an object is indexed for property assignment or creation. | |
Deleters | Defines behavior for when an object is indexed for property deletion. |
Not all language bindings support all of the four kinds of special object behavior. When special operations are declared using operations with no identifier, then in language bindings that do not support the particular kind of special operations there simply will not be such functionality.
The following IDL fragment defines an interface with a getter and a setter:
[Exposed =Window ]interface Dictionary {readonly attribute unsigned long propertyCount ;getter double (DOMString propertyName );setter undefined (DOMString propertyName ,double propertyValue ); };
In language bindings that do not support property getters and setters, objects implementing Dictionary will not have that special behavior.
Defining a special operation with an identifier is equivalent to separating the special operation out into its own declaration without an identifier. This approach is allowed to simplify method steps of an interface’s operations.
The following two interfaces are equivalent:
[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 ); };
A given special keyword must not appear twice on an operation.
Getters and setters come in two varieties: ones that
take a DOMString
as a property name,
known as named property getters and named property setters,
and ones that take an unsigned long
as a property index, known as indexed property getters and indexed property setters.
There is only one variety of deleter: named property deleters.
See § 2.5.6.1 Indexed properties and § 2.5.6.2 Named properties for details.
On a given interface, there must exist at most one named property deleter, and at most one of each variety of getter and setter.
If an interface has a setter of a given variety, then it must also have a getter of that variety. If it has a named property deleter, then it must also have a named property getter.
Special operations declared using operations must not be variadic nor have any optional arguments.
If an object implements more than one interface that defines a given special operation, then it is undefined which (if any) special operation is invoked for that operation.
2.5.6.1. Indexed properties
An interface that defines an indexed property getter is said to support indexed properties. By extension, a platform object is said to support indexed properties if it implements an interface that itself does.
If an interface supports indexed properties, then the interface definition must be accompanied by a description of what indices the object can be indexed with at any given time. These indices are called the supported property indices.
Interfaces that support indexed properties must define
an integer-typed attribute named "length
".
Indexed property getters must
be declared to take a single unsigned long
argument.
Indexed property setters must
be declared to take two arguments, where the first is an 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 ); };
The following requirements apply to the definitions of indexed property getters and setters:
-
If an indexed property getter was specified using an operation with an identifier, then the value returned when indexing the object with a given supported property index is the value that would be returned by invoking the operation, passing the index as its only argument. If the operation used to declare the indexed property getter did not have an identifier, then the interface definition must be accompanied by a description of how to determine the value of an indexed property for a given index.
-
If an indexed property setter was specified using an operation with an identifier, then the behavior that occurs when indexing the object for property assignment with a given supported property index and value is the same as if the operation is invoked, passing the index as the first argument and the value as the second argument. If the operation used to declare the indexed property setter did not have an identifier, then the interface definition must be accompanied by a description of how to set the value of an existing indexed property and how to set the value of a new indexed property for a given property index and value.
Note that if an indexed property getter or setter is specified using an operation with an identifier, then indexing an object with an integer that is not a supported property index does not necessarily elicit the same behavior as invoking the operation with that index. The actual behavior in this case is language binding specific.
In the JavaScript language binding, a regular property lookup is done. For example, take the following IDL:
[Exposed =Window ]interface A {getter DOMString toWord (unsigned long index ); };
Assume that an object implementing A
has supported property indices in the range 0 ≤ index < 2. Also assume that toWord is defined to return
its argument converted into an English word. The behavior when invoking the operation with an out of range index
is different from indexing the object directly:
var a= getA(); a. toWord( 0 ); // Evalautes to "zero". a[ 0 ]; // Also evaluates to "zero". a. toWord( 5 ); // Evaluates to "five". a[ 5 ]; // Evaluates to undefined, since there is no property "5".
The following IDL fragment defines an interface OrderedMap
which allows
retrieving and setting values by name or by index number:
[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 ); };
Since all of the special operations are declared using
operations with identifiers, the only additional prose
that is necessary is that which describes what keys those sets
have. Assuming that the get()
operation is
defined to return OrderedMap
, then the following
two sentences would suffice:
An object map implementing
OrderedMap
supports indexed properties with indices in the range 0 ≤ index <map.size
.Such objects also support a named property for every name that, if passed to
get()
, would return a non-null value.
As described in § 3.9 Legacy platform objects,
a JavaScript implementation would create
properties on a legacy platform object implementing OrderedMap
that correspond to
entries in both the named and indexed property sets.
These properties can then be used to interact
with the object in the same way as invoking the object’s
methods, as demonstrated below:
// Assume map is a legacy platform object implementing the OrderedMap interface. var map= getOrderedMap(); var x, y; x= map[ 0 ]; // If map.length > 0, then this is equivalent to: // // x = map.getByIndex(0) // // since a property named "0" will have been placed on map. // Otherwise, x will be set to undefined, since there will be // no property named "0" on map. map[ 1 ] = false ; // This will do the equivalent of: // // map.setByIndex(1, false) y= map. apple; // If there exists a named property named "apple", then this // will be equivalent to: // // y = map.get('apple') // // since a property named "apple" will have been placed on // map. Otherwise, y will be set to undefined, since there // will be no property named "apple" on map. map. berry= 123 ; // This will do the equivalent of: // // map.set('berry', 123) delete map. cake; // If a named property named "cake" exists, then the "cake" // property will be deleted, and then the equivalent to the // following will be performed: // // map.remove("cake")
2.5.6.2. Named properties
An interface that defines a named property getter is said to support named properties. By extension, a platform object is said to support named properties if it implements an interface that itself does.
If an interface supports named properties, then the interface definition must be accompanied by a description of the ordered set of names that can be used to index the object at any given time. These names are called the supported property names.
Named property getters and deleters must
be declared to take a single DOMString
argument.
Named property setters must
be declared to take two arguments, where the first is a 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 ); };
The following requirements apply to the definitions of named property getters, setters and deleters:
-
If a named property getter was specified using an operation with an identifier, then the value returned when indexing the object with a given supported property name is the value that would be returned by invoking the operation, passing the name as its only argument. If the operation used to declare the named property getter did not have an identifier, then the interface definition must be accompanied by a description of how to determine the value of a named property for a given property name.
-
If a named property setter was specified using an operation with an identifier, then the behavior that occurs when indexing the object for property assignment with a given supported property name and value is the same as if the operation is invoked, passing the name as the first argument and the value as the second argument. If the operation used to declare the named property setter did not have an identifier, then the interface definition must be accompanied by a description of how to set the value of an existing named property and how to set the value of a new named property for a given property name and value.
-
If a named property deleter was specified using an operation with an identifier, then the behavior that occurs when indexing the object for property deletion with a given supported property name is the same as if the operation is invoked, passing the name as the only argument. If the operation used to declare the named property deleter did not have an identifier, then the interface definition must be accompanied by a description of how to delete an existing named property for a given property name.
Note: As with indexed properties, if an named property getter, setter or deleter is specified using an operation with an identifier, then indexing an object with a name that is not a supported property name does not necessarily elicit the same behavior as invoking the operation with that name; the behavior is language binding specific.
2.5.7. Static attributes and operations
Static attributes and static operations are ones that
are not associated with a particular instance of the interface on which it is declared, and is instead associated with the interface
itself. Static attributes and operations are declared by using the
It is language binding specific whether it is possible to invoke a static operation or get or set a static attribute through a reference to an instance of the interface.
StaticMember ::static StaticMemberRest
StaticMemberRest ::OptionalReadOnly AttributeRest RegularOperation
The following IDL fragment defines an interface Circle
that has a static
operation declared on it:
[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 ); };
In the JavaScript language binding, the function object for triangulate
and the accessor property for triangulationCount
will exist on the interface object for Circle
:
var circles= getCircles(); // an Array of Circle objects typeof Circle. triangulate; // Evaluates to "function" typeof Circle. triangulationCount; // Evaluates to "number" Circle. prototype. triangulate; // Evaluates to undefined Circle. prototype. triangulationCount; // Also evaluates to undefined circles[ 0 ]. triangulate; // As does this circles[ 0 ]. triangulationCount; // And this // Call the static operation var triangulationPoint= Circle. triangulate( circles[ 0 ], circles[ 1 ], circles[ 2 ]); // Find out how many triangulations we have done window. alert( Circle. triangulationCount);
2.5.8. Overloading
If a regular operation or static operation defined on an interface has an identifier that is the same as the identifier of another operation on that interface of the same kind (regular or static), then the operation is said to be overloaded. When the identifier of an overloaded operation is used to invoke one of the operations on an object that implements the interface, the number and types of the arguments passed to the operation determine which of the overloaded operations is actually invoked. Constructor operations can be overloaded too. There are some restrictions on the arguments that overloaded operations and constructors can be specified to take, and in order to describe these restrictions, the notion of an effective overload set is used.
A set of overloaded operations must either:
-
contain no operations whose return type is a promise type;
-
only contain operations whose return type is a promise type.
Operations must not be overloaded across interface, partial interface, interface mixin, and partial interface mixin definitions.
For example, the overloads for both f and g are disallowed:
[Exposed =Window ]interface A {undefined f (); };partial interface A {undefined f (double x );undefined g (); };partial interface A {undefined g (DOMString x ); };
Note that constructor operations and
[LegacyFactoryFunction
] extended attributes are disallowed from appearing
on partial interface definitions,
so there is no need to also disallow overloading for constructors.
An effective overload set represents the allowable invocations for a particular operation,
constructor (specified with a constructor operation or [LegacyFactoryFunction
]), or callback function.
The algorithm to compute the effective overload set operates on one of the following four types of IDL constructs, and listed with them below are
the inputs to the algorithm needed to compute the set.
- For regular operations
- For static operations
-
-
the interface on which the operations are to be found
-
the identifier of the operations
-
the number of arguments to be passed
-
- For constructors
-
-
the interface on which the constructor operations are to be found
-
the number of arguments to be passed
-
- For legacy factory functions
-
-
the interface on which the [
LegacyFactoryFunction
] extended attributes are to be found -
the identifier of the legacy factory function
-
the number of arguments to be passed
-
An effective overload set is used, among other things, to determine whether there are ambiguities in the overloaded operations and constructors specified on an interface.
The items of an effective overload set are tuples of the form (callable, type list, optionality list) whose items are described below:
-
A callable is an operation if the effective overload set is for regular operations, static operations, or constructor operations; and it is an extended attribute if the effective overload set is for legacy factory functions.
-
A type list is a list of IDL types.
-
An optionality list is a list of three possible optionality values – "required", "optional" or "variadic" – indicating whether the argument at a given index was declared as being optional or corresponds to a variadic argument.
Each tuple represents an allowable invocation of the operation, constructor, or callback function with an argument value list of the given types. Due to the use of optional arguments and variadic operations and constructors, there may be multiple items in an effective overload set identifying the same operation or constructor.
-
the identifier of the operation or legacy factory function is A
-
the argument count is N
-
the interface is I
Whenever an argument of an extended attribute is mentioned, it is referring to an argument of the extended attribute’s named argument list.
-
Let S be an ordered set.
-
Let F be an ordered set with items as follows, according to the kind of effective overload set:
- For regular operations
-
The elements of F are the regular operations with identifier A defined on interface I.
- For static operations
-
The elements of F are the static operations with identifier A defined on interface I.
- For constructors
-
The elements of F are the constructor operations on interface I.
- For legacy factory functions
-
The elements of F are the [
LegacyFactoryFunction
] extended attributes on interface I whose named argument lists' identifiers are A.
-
Let maxarg be the maximum number of arguments the operations, legacy factory functions, or callback functions in F are declared to take. For variadic operations and legacy factory functions, the argument on which the ellipsis appears counts as a single argument.
Note: So
undefined f(long x, long... y);
is considered to be declared to take two arguments. -
Let max be max(maxarg, N).
-
For each operation or extended attribute X in F:
-
Let arguments be the list of arguments X is declared to take.
-
Let n be the size of arguments.
-
Let types be a type list.
-
Let optionalityValues be an optionality list.
-
For each argument in arguments:
-
If X is declared to be variadic, then:
-
Let i be n − 1.
-
While i ≥ 0:
-
If arguments[i] is not optional (i.e., it is not marked as "optional" and is not a final, variadic argument), then break.
-
Let t be a type list.
-
Let o be an optionality list.
-
Append the tuple (X, t, o) to S.
Note: if i is 0, this means to add to S the tuple (X, « », « »); (where "« »" represents an empty list).
-
Set i to i − 1.
-
-
-
Return S.
For the following interface:
[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 ); };
assuming Node
and Event
are two other interfaces of which no object can implement both,
the effective overload set for regular operations with
identifier f
and argument count 4 is:
« (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 ») »
Two types are distinguishable if the following algorithm returns true.
-
If one type includes a nullable type and the other type either includes a nullable type, is a union type with flattened member types including a dictionary type, or is a dictionary type, return false.
-
If both types are either a union type or nullable union type, return true if each member type of the one is distinguishable with each member type of the other, or false otherwise.
-
If one type is a union type or nullable union type, return true if each member type of the union type is distinguishable with the non-union type, or false otherwise.
-
Consider the two "innermost" types derived by taking each type’s inner type if it is an annotated type, and then taking its inner type inner type if the result is a nullable type. If these two innermost types appear or are in categories appearing in the following table and there is a “●” mark in the corresponding entry or there is a letter in the corresponding entry and the designated additional requirement below the table is satisfied, then return true. Otherwise return false.
Categories:
- interface-like
- dictionary-like
- sequence-like
undefinedbooleannumeric typesbigintstring typesobjectsymbolinterface-likecallback functiondictionary-likesequence-likeundefined ● ● ● ● ● ● ● ● ● boolean ● ● ● ● ● ● ● ● ● numeric types (b) ● ● ● ● ● ● ● bigint ● ● ● ● ● ● ● string types ● ● ● ● ● ● object ● symbol ● ● ● ● interface-like (a) ● ● ● callback function (c) ● dictionary-like ● sequence-like -
The two identified interface-like types are not the same, and no single platform object implements both interface-like types.
-
The types are distinguishable, but there is a separate restriction on their use in overloading below. Please also note the advice about using unions of these types.
-
A callback function that does not have [
LegacyTreatNonObjectAsNull
] extended attribute is distinguishable from a type in the dictionary-like category.For example, when converting an ECMAScript value to union type which includes a callback function and a dictionary-like type, if the value is callable, then it is converted to a callback function. Otherwise, it is converted to a dictionary-like type.
double
andDOMString
are distinguishable because there is a ● at the intersection of numeric types with string types.double
andlong
are not distinguishable because they are both numeric types, and there is no ● or letter at the intersection of numeric types with numeric types.Given:callback interface CBIface {undefined handle (); }; [Exposed =Window ]interface Iface {attribute DOMString attr2 ; };dictionary Dict {DOMString field1 ; };CBIface
is distinguishable fromIface
because there’s a ● at the intersection of dictionary-like and interface-like, but it is not distinguishable fromDict
because there’s no ● at the intersection of dictionary-like and itself.Promise types do not appear in the above table, and as a consequence are not distinguishable with any other type.
If there is more than one item in an effective overload set that has a given type list size, then for those items there must be an index i such that for each pair of items the types at index i are distinguishable. The lowest such index is termed the distinguishing argument index for the items of the effective overload set with the given type list size.
An effective overload set must not contain more than
one item with the same type list size, where one item has a bigint
argument at the distinguishing argument index and another has a numeric type argument at the distinguishing argument index.
Consider the effective overload set shown in the previous example.
There are multiple items in the set with type lists 2, 3 and 4.
For each of these type list size, the distinguishing argument index is 0, since Node
and Event
are distinguishable.
The following use of overloading however is invalid:
[Exposed =Window ]interface B {undefined f (DOMString x );undefined f (USVString x ); };
In addition, for each index j, where j is less than the distinguishing argument index for a given type list size, the types at index j in all of the items' type lists must be the same, and the optionality values at index j in all of the items' optionality lists must be the same.
The following is invalid:
[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 ); };
For argument count 4, the effective overload set is:
« (f1, « DOMString », « required »), (f2, « long, double, Node, Node », « required, required, required, required »), (f3, « double, double, DOMString, Node », « required, required, required, required ») »
Looking at items with type list size 4, the distinguishing argument index is 2, since Node
and DOMString
are distinguishable.
However, since the arguments in these two overloads at index 0 are different,
the overloading is invalid.
2.5.8.1. Overloading vs. union types
This section is informative.
For specifications defining IDL operations, it might seem that overloads and a combination of union types and optional arguments have some feature overlap.
It is first important to note that overloads have different behaviors than union
types or optional arguments, and one cannot be fully defined using the other (unless,
of course, additional prose is provided, which can defeat the purpose of the Web IDL type system).
For example, consider the stroke()
operations defined on the CanvasDrawPath
interface [HTML]:
interface CanvasDrawPathExcerpt {undefined stroke ();undefined stroke (Path2D path ); };
Per the JavaScript language binding, calling stroke(undefined)
on an object
implementing CanvasDrawPathExcerpt
would attempt to call the second
overload, yielding a TypeError
since Path2D
. However, if the operations were instead
defined with optional arguments and merged into one,
interface CanvasDrawPathExcerptOptional {undefined stroke (optional Path2D path ); };
the overload resolution algorithm would treat the path argument as missing
given the same call stroke(undefined)
, and not throw any exceptions.
Note: For this particular example, the latter behavior is actually what Web developers would
generally expect. If CanvasDrawPath
were to be designed today, optional arguments would be
used for stroke()
.
Additionally, there are semantic differences as well. Union types are usually used in the sense that "any of the types would work in about the same way". In contrast, overloaded operations are designed to map well to language features such as C++ overloading, and are usually a better fit for operations with more substantial differences in what they do given arguments of different types. However, in most cases, operations with such substantial differences are best off with different names to avoid confusion for Web developers, since the JavaScript language does not provide language-level overloading. As such, overloads are rarely appropriate for new APIs, instead often appearing in legacy APIs or in specialized circumstances.
That being said, we offer the following recommendations and examples in case of difficulties to determine what Web IDL language feature to use:
-
In the unusual case where the operation needs to return values of different types for different argument types, overloading will result in more expressive IDL fragments. This is almost never appropriate API design, and separate operations with distinct names usually are a better choice for such cases.
Suppose there is an operation
calculate()
that accepts along
,DOMString
, orCalculatableInterface
(an interface type) as its only argument, and returns a value of the same type as its argument. It would be clearer to write the IDL fragment using overloaded operations asinterface A {long calculate (long input );DOMString calculate (DOMString input );CalculatableInterface calculate (CalculatableInterface input ); };than using a union type with a typedef as
typedef (long or DOMString or CalculatableInterface )Calculatable ;interface A {Calculatable calculate (Calculatable input ); };which does not convey the fact that the return value is always of the same type as input.
If the specified
calculate()
is a new API and does not have any compatibility concerns, it is suggested to use different names for the overloaded operations, perhaps asinterface A {long calculateNumber (long input );DOMString calculateString (DOMString input );CalculatableInterface calculateCalculatableInterface (CalculatableInterface input ); };which allows Web developers to write explicit and unambiguous code.
-
When the operation has significantly different semantics for different argument types or lengths, overloading is preferred. Again, in such scenarios, it is usually better to create separate operations with distinct names, but legacy APIs sometimes follow this pattern.
As an example, the
supports(property, value)
andsupports(conditionText)
operations of theCSS
interface are defined as the following IDL fragment [CSS3-CONDITIONAL] [CSSOM].partial interface CSS {static boolean supports (CSSOMString property ,CSSOMString value );static boolean supports (CSSOMString conditionText ); };Using optional arguments one can rewrite the IDL fragment as follows:
partial interface CSSExcerptOptional {static boolean supports (CSSOMString propertyOrConditionText ,optional CSSOMString value ); };Even though the IDL is shorter in the second version, two distinctively different concepts are conflated in the first argument. Without overloads, the question "is property or conditionText paired with value?" is much more difficult to answer without reading the method steps of the operation. This makes the second version remarkably less readable than the first.
Another consideration is that the method steps for overloaded operations can be specified in separate blocks, which can aid in both reading and writing specifications. This is not the case for optional arguments. This means that in the first case the specification author can write the method steps of the operations as:
The
supports(property, value)
method steps are:-
…
The
supports(conditionText)
method steps are:-
…
Yet using value as an optional argument, the specification author has to use more boilerplate-style text to effectively replicate the overload resolution algorithm.
The
supports(propertyOrConditionText, value)
method steps are:-
If value is given, then:
-
Let property be propertyOrConditionText.
-
…
-
-
Otherwise:
-
Let conditionText be propertyOrConditionText.
-
…
-
If the two overloads have little to no shared parts, it is better to leave overload resolution to the IDL mechanism.
-
-
If the operation accepts multiple types for multiple arguments with no coupling between types of different arguments, union types can sometimes be the only viable solution.
typedef (long long or DOMString or CalculatableInterface )SupportedArgument ;interface A {undefined add (SupportedArgument operand1 ,SupportedArgument operand2 ); };For the
add()
operation above, to specify it using overloads would requireinterface 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 ); };and nine times the corresponding prose!
-
Specification authors are encouraged to treat missing argument and
undefined argument the same way in the JavaScript language binding.Given the following IDL fragment:
interface A {undefined foo ();undefined foo (Node ?arg ); };Using the JavaScript language binding, calling
foo(undefined)
andfoo(null)
would both run the steps corresponding to thefoo(arg)
operation, with arg set to null, whilefoo()
alone would go to the first overload. This can be a surprising behavior for many API users. Instead, specification authors are encouraged to use an optional argument, which would categorize bothfoo()
andfoo(undefined)
as "arg is missing".interface A {undefined foo (optional Node ?arg ); };In general, optionality is best expressed using the
optional keyword, and not using overloads.
When the case fits none of the categories above, it is up to the specification author to choose the style, since it is most likely that either style would sufficiently and conveniently describe the intended behavior. However, the definition and conversion algorithms of union types and optional arguments are simpler to implement and reason about than those of overloads, and usually result in more idiomatic APIs in the JavaScript language binding. Thus, unless any other considerations apply, union types, optional arguments, or both are the default choice.
Specifications are also free to mix and match union types and overloads, if the author finds it appropriate and convenient.
2.5.9. Iterable declarations
An interface can be declared to be iterable by using an iterable declaration (matching
interface interface_identifier {iterable <value_type >;iterable <key_type ,value_type >; };
Objects implementing an interface that is declared to be iterable support being iterated over to obtain a sequence of values.
Note: In the JavaScript language binding, an interface that is iterable
will have entries
, forEach
, keys
, values
, and %Symbol.iterator%
properties on its interface prototype object.
If a single type parameter is given, then the interface has a value iterator and provides values of the specified type. If two type parameters are given, then the interface has a pair iterator and provides value pairs with the given types.
A value pair, given a key type and a value type, is a struct with two items:
-
an item whose name is "key", which is referred to as the value pair's key, and whose value is an IDL value of the key type;
-
an item whose name is "value", which is referred to as the value pair's value, and whose value is an IDL value of the value type.
A value iterator must only be declared on an interface that supports indexed properties. The value-type of the value iterator must be the same as the type returned by the indexed property getter. A value iterator is implicitly defined to iterate over the object’s indexed properties.
A pair iterator must not be declared on an interface that supports indexed properties.
Prose accompanying an interface with a pair iterator must define a list of value pairs for each instance of the interface, which is the list of value pairs to iterate over.
The JavaScript forEach method that is generated for a value iterator invokes its callback like Array.prototype.forEach does, and the forEach method for a pair iterator invokes its callback like Map.prototype.forEach does.
Since value iterators are currently allowed only on interfaces that support indexed properties, it makes sense to use an Array-like forEach method. There could be a need for value iterators (a) on interfaces that do not support indexed properties, or (b) with a forEach method that instead invokes its callback like Set.prototype.forEach (where the key is the same as the value). If you’re creating an API that needs such a forEach method, please file an issue.
Note: This is how array iterator objects work.
For interfaces that support indexed properties,
the iterator objects returned by entries
, keys
, values
, and %Symbol.iterator%
are
actual array iterator objects.
Interfaces with an iterable declaration must not have any attributes, constants, or regular operations named "entries
", "forEach
", "keys
", or
"values
", or have any inherited interfaces that have attributes, constants,
or regular operations with these names.
Consider the following interface SessionManager
, which allows access to
a number of Session
objects keyed by username:
[Exposed =Window ]interface SessionManager {Session getSessionForUser (DOMString username );iterable <DOMString ,Session >; }; [Exposed =Window ]interface Session {readonly attribute DOMString username ; // ... };
The behavior of the iterator could be defined like so:
The value pairs to iterate over are the list of value pairs with the key being the username and the value being the open
Session
object on theSessionManager
object corresponding to that username, sorted by username.
In the JavaScript language binding, the interface prototype object for the SessionManager
interface has a values
method that is a function, which, when invoked,
returns an iterator object that itself has a next
method that returns the
next value to be iterated over. It has keys
and entries
methods that iterate over the usernames of session objects
and username/Session
object pairs, respectively. It also has
a %Symbol.iterator%
method that allows a SessionManager
to be used in a for..of
loop that has the same value as the entries
method:
// Get an instance of SessionManager. // Assume that it has sessions for two users, "anna" and "brian". var sm= getSessionManager(); typeof SessionManager. prototype. values; // Evaluates to "function" var it= sm. values(); // values() returns an iterator object String( it); // Evaluates to "[object SessionManager Iterator]" typeof it. next; // Evaluates to "function" // This loop will log "anna" and then "brian". for (;;) { let result= it. next(); if ( result. done) { break ; } let session= result. value; console. log( session. username); } // This loop will also log "anna" and then "brian". for ( let usernameof sm. keys()) { console. log( username); } // Yet another way of accomplishing the same. for ( let [ username, session] of sm) { console. log( username); }
An interface must not have more than one iterable declaration. The inherited interfaces of an interface with an iterable declaration must not also have an iterable declaration. An interface with an iterable declaration and its inherited interfaces must not have a maplike declaration, setlike declaration, or asynchronously iterable declaration.
The following extended attributes are applicable to iterable declarations:
[CrossOriginIsolated
],
[Exposed
], and
[SecureContext
].
Iterable ::iterable < TypeWithExtendedAttributes OptionalType > ;
OptionalType ::, TypeWithExtendedAttributes ε
2.5.10. Asynchronously iterable declarations
An interface can be declared to be asynchronously iterable by using an asynchronously iterable declaration (matching
interface interface_identifier {async iterable <value_type >;async iterable <value_type >(/* arguments... */);async iterable <key_type ,value_type >;async iterable <key_type ,value_type >(/* arguments... */); };
Objects that implement an interface that is declared to be asynchronously iterable support being iterated over asynchronously to obtain a sequence of values.
If a single type parameter is given, then the interface has a value asynchronously iterable declaration and asynchronously provides values of the specified type. If two type parameters are given, then the interface has a pair asynchronously iterable declaration and asynchronously provides value pairs with the given types.
If given, an asynchronously iterable declaration's arguments (matching
%Symbol.asyncIterator%
and values
properties on its interface prototype object. If the interface has a pair asynchronously iterable declaration, it will additionally have entries
and keys
properties. All of these
methods can be passed optional arguments, which correspond to the argument list in the asynchronously iterable declaration, and are processed by the asynchronous iterator initialization steps, if any exist.
With this in mind, the requirement that all arguments be optional ensures that, in the
JavaScript binding, for
-await
-of
can work directly on
instances of the interface, since for
-await
-of
calls the %Symbol.asyncIterator%
method with no arguments.
Prose accompanying an interface with an asynchronously iterable declaration must define a get the next iteration result algorithm.
This algorithm receives the instance of the interface that is being iterated, as well as the
async iterator itself (which can be useful for storing state).
It must return a Promise
that either rejects, resolves with a special end of
iteration value to signal the end of the iteration, or resolves with one of the following:
- for value asynchronously iterable declarations:
-
a value of the type given in the declaration;
- for pair asynchronously iterable declarations:
-
a tuple containing a value of the first type given in the declaration, and a value of the second type given in the declaration.
The prose may also define an asynchronous iterator return algorithm. This
algorithm receives the instance of the interface that is being iterated, the async iterator
itself, and a single argument value of type any
. This algorithm is invoked in the case of
premature termination of the async iterator. It must return a Promise
; if that promise
fulfills, its fulfillment value will be ignored, but if it rejects, that failure will be passed on
to users of the async iterator API.
In the JavaScript binding, this algorithm allows customizing the behavior when the
async iterator’s return()
method is invoked. This most commonly occurs when a break
or return
statement causes an exit from a for
-await
-of
loop.
We could add a similar hook for throw()
. So far there has been no need,
but if you are creating an API that needs such capabilities, please file an issue.
The prose may also define asynchronous iterator initialization steps. These receive the instance of the interface being iterated, the newly-created iterator object, and a list of IDL values representing the arguments passed, if any.
Interfaces with an asynchronously iterable declaration must not have any attributes, constants, or regular operations named "entries
", "keys
", or
"values
", or have any inherited interfaces that have attributes, constants,
or regular operations with these names.
Consider the following interface SessionManager
, which allows access
to a number of Session
objects keyed by username:
[Exposed =Window ]interface SessionManager {Session getSessionForUser (DOMString username );async iterable <DOMString ,Session >; }; [Exposed =Window ]interface Session {readonly attribute DOMString username ; // ... };
The behavior of the iterator could be defined like so:
The asynchronous iterator initialization steps for a
SessionManager
async iterator iterator are:
Set iterator’s current state to "not yet started".
To get the next iteration result for a
SessionManager
manager and its async iterator iterator:
Let promise be a new promise.
Let key be the following value, if it exists, or null otherwise:
- If iterator’s current state is "not yet started"
the smallest username in manager’s open sessions, in lexicographical order
- Otherwise
the smallest username in manager’s open sessions that is greater than iterator’s current state, in lexicographical order
Note: iterator’s current state might no longer be present in the open sessions.
If key is null, then:
Resolve promise with end of iteration.
Otherwise:
Let session be the
Session
object corresponding to key.Resolve promise with (username, session).
Set iterator’s current state to username.
Return promise.
In the JavaScript language binding, the interface prototype object for the SessionManager
interface has a values
method that is a
function, which, when invoked, returns an asynchronous iterator object that itself has a next
method that returns the next value to be iterated over.
It has keys
and entries
methods that iterate over the usernames of
session objects and (username, Session
) object pairs, respectively.
It also has a %Symbol.asyncIterator%
method that allows a SessionManager
to be used in a for await..of
loop that has the same value as the entries
method:
// Get an instance of SessionManager. // Assume that it has sessions for two users, "anna" and "brian". var sm= getSessionManager(); typeof SessionManager. prototype. values; // Evaluates to "function" var it= sm. values(); // values() returns an iterator object typeof it. next; // Evaluates to "function" // This loop will log "anna" and then "brian". for await ( let usernameof sm. keys()) { console. log( username); } // Yet another way of accomplishing the same. for await ( let [ username, session] of sm) { console. log( username); }
An interface must not have more than one asynchronously iterable declaration. The inherited interfaces of an interface with an asynchronously iterable declaration must not also have an asynchronously iterable declaration. An interface with an asynchronously iterable declaration and its inherited interfaces must not have a maplike declaration, setlike declaration, or iterable declaration.
The following extended attributes are applicable to asynchronously iterable declarations:
[CrossOriginIsolated
],
[Exposed
], and
[SecureContext
].
these extended attributes are not currently taken into account. When they are, the effect will be as you would expect.
AsyncIterable ::async iterable < TypeWithExtendedAttributes OptionalType > OptionalArgumentList ;
OptionalArgumentList ::( ArgumentList ) ε
2.5.11. Maplike declarations
An interface can be declared to be maplike by using a maplike declaration (matching
interface interface_identifier {readonly maplike <key_type ,value_type >;maplike <key_type ,value_type >; };
Objects implementing an interface that is declared to be maplike represent an ordered map of key–value pairs, initially empty, known as that object’s map entries. The types used for the keys and values are given in the angle brackets of the maplike declaration. Keys are required to be unique.
Specification authors can modify the contents of the map entries, which will automatically be reflected in the contents of the object as observed by JavaScript code.
Maplike interfaces support an API for querying the map entries
appropriate for the language binding. If the
Note: In the JavaScript language binding, the API for interacting
with the map entries is similar to that available on JavaScript Map
objects. If the entries
, forEach
, get
, has
, keys
, values
, %Symbol.iterator%
methods, and a size
getter.
For read–write maplikes, it also includes clear
, delete
, and set
methods.
Maplike interfaces must not have any attributes, constants, or regular operations named
"entries
", "forEach
", "get
", "has
",
"keys
", "size
", or "values
", or have any inherited interfaces that have attributes, constants, or regular operations with
these names.
Read–write maplike interfaces must not
have any attributes or constants named
"clear
", "delete
",
or "set
", or have any inherited interfaces that have attributes or constants with these names.
Note: Read-write maplike interfaces can have regular operations named
"clear
", "delete
", or "set
", which will override the default
implementation of those methods (defined in § 3.7.11 Maplike declarations). If such regular operations are
defined, they must match the input and output expectations of each method, defined in their default
implementation sections.
An interface must not have more than one maplike declaration. The inherited interfaces of a maplike interface must not also have a maplike declaration. A maplike interface and its inherited interfaces must not have an iterable declaration, an asynchronously iterable declaration, a setlike declaration, or an indexed property getter.
ReadOnlyMember ::readonly ReadOnlyMemberRest
ReadWriteMaplike ::MaplikeRest
MaplikeRest ::maplike < TypeWithExtendedAttributes , TypeWithExtendedAttributes > ;
No extended attributes defined in this specification are applicable to maplike declarations.
Add example.
2.5.12. Setlike declarations
An interface can be declared to be setlike by using a setlike declaration (matching
interface interface_identifier {readonly setlike <type >;setlike <type >; };
Objects implementing an interface that is declared to be setlike represent an ordered set of values, initially empty, known as that object’s set entries. The type of the values is given in the angle brackets of the setlike declaration. Values are required to be unique.
Specification authors can modify the contents of the set entries, which will automatically be reflected in the contents of the object as observed by JavaScript code.
Setlike interfaces support an API for querying the set entries
appropriate for the language binding. If the
Note: In the JavaScript language binding, the API for interacting
with the set entries is similar to that available on JavaScript Set
objects. If the entries
, forEach
, has
, keys
, values
, %Symbol.iterator%
methods, and a size
getter.
For read–write setlikes, it also includes add
, clear
, and delete
methods.
Setlike interfaces must not have any attributes, constants, or regular operations named
"entries
", "forEach
", "has
", "keys
",
"size
", or "values
", or have any inherited interfaces that have attributes, constants, or regular operations with these names.
Read–write setlike interfaces must not
have any attributes or constants named
"add
", "clear
",
or "delete
", or have any inherited interfaces that have attributes or constants with these names.
Note: Read-write setlike interfaces can have regular operations named
"add
", "clear
", or "delete
", which will override the default
implementation of those methods (defined in § 3.7.12 Setlike declarations). If such regular operations are
defined, they must match the input and output expectations of each method, defined in their default
implementation sections.
An interface must not have more than one setlike declaration. The inherited interfaces of a setlike interface must not also have a setlike declaration. A setlike interface and its inherited interfaces must not have an iterable declaration, an asynchronously iterable declaration, a maplike declaration, or an indexed property getter.
ReadOnlyMember ::readonly ReadOnlyMemberRest
ReadWriteSetlike ::SetlikeRest
SetlikeRest ::setlike < TypeWithExtendedAttributes > ;
No extended attributes defined in this specification are applicable to setlike declarations.
Add example.
2.6. Namespaces
A namespace is a definition (matching
namespace identifier { /* namespace_members... */ };
A namespace is a specification of a set of namespace members (matching
As with interfaces, the IDL for namespaces can be split into multiple parts by using partial namespace definitions
(matching
namespace SomeNamespace { /* namespace_members... */ };partial namespace SomeNamespace { /* namespace_members... */ };
Note: As with partial interface definitions, partial namespace definitions are intended for use as a specification editorial aide, allowing the definition of a namespace to be separated over more than one section of the document, and sometimes multiple documents.
The order that members appear in has significance for property enumeration in the JavaScript binding.
Note that unlike interfaces or dictionaries, namespaces do not create types.
Of the extended attributes defined in this specification, only the [CrossOriginIsolated
], [Exposed
], and [SecureContext
] extended attributes are applicable to namespaces.
Namespaces must be annotated with the [Exposed
] extended attribute.
Partial ::partial PartialDefinition
Namespace ::namespace identifier { NamespaceMembers } ;
NamespaceMembers ::ExtendedAttributeList NamespaceMember NamespaceMembers ε
NamespaceMember ::RegularOperation readonly AttributeRest Const
The following IDL fragment defines a namespace.
namespace VectorUtils {readonly attribute Vector unit ;double dotProduct (Vector x ,Vector y );Vector crossProduct (Vector x ,Vector y ); };
A JavaScript implementation would then expose a global VectorUtils
data property which was a simple object (with prototype %Object.prototype%
) with enumerable data properties for each declared operation, and
enumerable get-only accessors for each declared attribute:
Object. getPrototypeOf( VectorUtils); // Evaluates to Object.prototype. Object. keys( VectorUtils); // Evaluates to ["dotProduct", "crossProduct"]. Object. getOwnPropertyDescriptor( VectorUtils, "dotProduct" ); // Evaluates to { value: <a function>, enumerable: true, configurable: true, writable: true }. Object. getOwnPropertyDescriptor( VectorUtils, "unit" ); // Evaluates to { get: <a function>, enumerable: true, configurable: true }.
2.7. Dictionaries
A dictionary is a definition (matching
dictionary identifier { /* dictionary_members... */ };
Dictionary instances do not retain a reference to their language-specific representations (e.g., the corresponding JavaScript object). So for example, returning a dictionary from an operation will result in a new JavaScript object being created from the current values of the dictionary. And, an operation that accepts a dictionary as an argument will perform a one-time conversion from the given JavaScript value into the dictionary, based on the current properties of the JavaScript object. Modifications to the dictionary will not be reflected in the corresponding JavaScript object, and vice-versa.
Dictionaries must not be used as the type of an attribute or constant.
A dictionary can be defined to inherit from another dictionary. If the identifier of the dictionary is followed by a colon and a identifier, then that identifier identifies the inherited dictionary. The identifier must identify a dictionary.
A dictionary must not be declared such that its inheritance hierarchy has a cycle. That is, a dictionary A cannot inherit from itself, nor can it inherit from another dictionary B that inherits from A, and so on.
dictionary Base { /* dictionary_members... */ };dictionary Derived :Base { /* dictionary_members... */ };
The inherited dictionaries of a given dictionary D is the set of all dictionaries that D inherits from, directly or indirectly. If D does not inherit from another dictionary, then the set is empty. Otherwise, the set includes the dictionary E that D inherits from and all of E’s inherited dictionaries.
Dictionary members can be specified as required, meaning that converting a language-specific value to a dictionary requires providing a value for that member. Any dictionary member that is not required is optional.
Note that specifying dictionary members as required only has an observable effect when converting other representations of dictionaries (like a JavaScript value supplied as an argument to an operation) to an IDL dictionary. Specification authors should leave the members optional in all other cases, including when a dictionary type is used solely as the return type of operations.
A given dictionary value of type D can have entries for each of the dictionary members defined on D and on any of D’s inherited dictionaries. Dictionary members that are specified as required, or that are specified as having a default value, will always have such corresponding entries. Other members' entries might or might not exist in the dictionary value.
In the JavaScript binding, a value of
As with operation argument default values, it is strongly
encouraged not to use boolean
-typed dictionary members, as this can be confusing for authors who might
otherwise expect the default conversion of
An ordered map with string keys can be implicitly treated as a dictionary value of a specific dictionary D if all of its entries correspond to dictionary members, as long as those entries have the correct types, and there are entries present for any required or defaulted dictionary members.
dictionary Descriptor {DOMString name ;sequence <unsigned long >serviceIdentifiers ; };
A Descriptor
dictionary could be created as in the following steps:
-
Let identifiers be « 1, 3, 7 ».
-
Return «[ "name" → "test", "serviceIdentifiers" → identifiers ]».
Each dictionary member (matching
If the type of the dictionary member, after resolving typedefs, is a nullable type, its inner type must not be a dictionary type.
dictionary identifier {type identifier ; };
If the identifier for an optional dictionary member is followed by a
U+003D (=) and a value (matching
dictionary identifier {type identifier = "value"; };
When a boolean literal token (
If the type of the dictionary member is an enumeration, then its default value if specified must be one of the enumeration’s values.
If the type of the dictionary member is preceded by the
dictionary identifier {required type identifier ; };
The type of a dictionary member must not include the dictionary it appears on. A type includes a dictionary D if at least one of the following is true:
-
the type is D
-
the type is a dictionary that inherits from D
-
the type is a nullable type whose inner type includes D
-
the type is a sequence type or frozen array whose element type includes D
-
the type is a union type, one of whose member types includes D
-
the type is a dictionary, one of whose members or inherited members has a type that includes D
-
the type is
record<K, V>
where V includes D
As with interfaces, the IDL for dictionaries can be split into multiple parts
by using partial dictionary definitions
(matching
dictionary SomeDictionary { /* dictionary_members... */ };partial dictionary SomeDictionary { /* dictionary_members... */ };
Note: As with partial interface definitions, partial dictionary definitions are intended for use as a specification editorial aide, allowing the definition of an interface to be separated over more than one section of the document, and sometimes multiple documents.
The order of the dictionary members on a given dictionary is such that inherited dictionary members are ordered before non-inherited members, and the dictionary members on the one dictionary definition (including any partial dictionary definitions) are ordered lexicographically by the Unicode codepoints that comprise their identifiers.
For example, with the following definitions:
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 ; };
the order of the dictionary members of a dictionary value of type C
is
c, d, g, h, a, b, e, f.
Dictionaries need to have their members ordered because in some language bindings the behavior observed when passing a dictionary value to a platform object depends on the order the dictionary members are fetched. For example, consider the following additional interface:
[Exposed =Window ]interface Something {undefined f (A a ); };
and this JavaScript code:
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);
The order that the dictionary members are fetched in determines
what values they will be taken to have. Since the order for A
is defined to be c then d,
the value for c will be 1 and the value for d will be 2.
The identifier of a dictionary member must not be the same as that of another dictionary member defined on the dictionary or on that dictionary’s inherited dictionaries.
No extended attributes are applicable to dictionaries.
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 ε
One use of dictionary types is to allow a number of optional arguments to an operation without being constrained as to the order they are specified at the call site. For example, consider the following IDL fragment:
[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 ); };
In a JavaScript implementation of the IDL, an Object
can be passed in for the optional PaintOptions
dictionary:
// Get an instance of GraphicsContext. var ctx= getGraphicsContext(); // Draw a rectangle. ctx. drawRectangle( 300 , 200 , { fillPattern: "red" , position: new Point( 10 , 10 ) });
The members of PaintOptions
are optional.
If fillPattern
is omitted, the definition of drawRectangle
can assume that it has the given default values
and not include explicit wording to handle its omission. drawRectangle
needs to explicitly handle the case where strokePattern
and position
are omitted.
2.8. Exceptions
An exception is a type of object that represents an error and
which can be thrown or treated as a first class value by implementations. Web IDL has a number of
pre-defined exceptions that specifications can reference and throw in their definition of
operations, attributes, and so on. Custom exception types can also be defined, as interfaces that inherit from DOMException
.
A simple exception is identified by one of the following types:
-
EvalError
-
RangeError
-
ReferenceError
-
TypeError
-
URIError
These correspond to all of the JavaScript error objects (apart from SyntaxError
and Error
, which are deliberately
omitted as they are reserved for use by the JavaScript parser and by authors, respectively). The
meaning of each simple exception matches its corresponding error object in the JavaScript
specification.
The second kind of exception is a DOMException
, which provides further
programmatically-introspectable detail on the error that occurred by giving a name.
Such names are drawn from the DOMException
names table below.
As DOMException
is an interface type, it can be used as a type in IDL. This
allows for example an operation to be declared to have a DOMException
return type. This
is generally a bad pattern, however, as exceptions are meant to be thrown and not returned.
The final kind of exception is a derived interface of DOMException
. These are more complicated,
and thus described in the dedicated section § 2.8.2 DOMException derived interfaces.
Simple exceptions can be created by providing their
type name. A DOMException
can be created by providing its name followed by DOMException
. Exceptions can also be thrown, by providing the same details
required to create one. In both cases, the caller may provide additional information
about what the exception indicates, which is useful when constructing the exception’s message.
Here is are some examples of wording to use to create and throw exceptions.
To throw a new simple exception whose type is TypeError
:
To throw a new DOMException
with name "NotAllowedError
":
To create a new DOMException
with name "SyntaxError
":
Let object be a newly created "
SyntaxError
"DOMException
.
To reject a promise with a new DOMException
with name "OperationError
":
Reject p with an "OperationError
"DOMException
.
An example of including additional information used to construct the exception message would be:
Throw a "SyntaxError
"DOMException
indicating that the given value had disallowed trailing spaces.
Such additional context is most helpful to implementers when it is not immediately obvious
why the exception is being thrown, e.g., because there are many different steps in the algorithm
which throw a "SyntaxError
" DOMException
. In contrast, if your specification throws a
"NotAllowedError
" DOMException
immediately after checking if the user has provided
permission to use a given feature, it’s fairly obvious what sort of message the implementation
ought to construct, and so specifying it is not necessary.
The resulting behavior from creating and throwing an exception is language binding specific.
See § 3.14.3 Creating and throwing exceptions for details on what creating and throwing an exception entails in the JavaScript language binding.
2.8.1. Base DOMException
error names
The DOMException
names table below lists all the
allowed names for instances of the base DOMException
interface, along with a
description of what such names mean, and legacy numeric error code values.
Interfaces inheriting from DOMException
, in the manner described
in § 2.8.2 DOMException derived interfaces, will have their own names, not listed in this table.
When creating or throwing a DOMException
, specifications must use
one of these names. If a specification author believes none of these names are a good fit for their
case, they must file an issue to discuss adding a new name to the shared namespace, so that the community can coordinate such
efforts. Note that adding new use-case-specific names is only important if you believe web
developers will discriminate multiple error conditions arising from a single API.
The DOMException
names marked as deprecated are kept for legacy purposes, but
their usage is discouraged.
Note: Don’t confuse the "SyntaxError
" DOMException
defined here
with JavaScript’s SyntaxError
.
"SyntaxError
" DOMException
is used to report parsing errors in web APIs,
for example when parsing selectors,
while the JavaScript SyntaxError
is reserved for the JavaScript parser.
To help disambiguate this further,
always favor the "SyntaxError
" DOMException
notation
over just using SyntaxError
to refer to the DOMException
. [DOM]
Name | Description | Legacy code name and value |
---|---|---|
"IndexSizeError "
| Deprecated. Use RangeError instead.
| INDEX_SIZE_ERR (1)
|
"HierarchyRequestError "
| The operation would yield an incorrect node tree. [DOM] | HIERARCHY_REQUEST_ERR (3)
|
"WrongDocumentError "
| The object is in the wrong document. [DOM] | WRONG_DOCUMENT_ERR (4)
|
"InvalidCharacterError "
| The string contains invalid characters. | INVALID_CHARACTER_ERR (5)
|
"NoModificationAllowedError "
| The object can not be modified. | NO_MODIFICATION_ALLOWED_ERR (7)
|
"NotFoundError "
| The object can not be found here. | NOT_FOUND_ERR (8)
|
"NotSupportedError "
| The operation is not supported. | NOT_SUPPORTED_ERR (9)
|
"InUseAttributeError "
| The attribute is in use by another element. [DOM] | INUSE_ATTRIBUTE_ERR (10)
|
"InvalidStateError "
| The object is in an invalid state. | INVALID_STATE_ERR (11)
|
"SyntaxError "
| The string did not match the expected pattern. | SYNTAX_ERR (12)
|
"InvalidModificationError "
| The object can not be modified in this way. | INVALID_MODIFICATION_ERR (13)
|
"NamespaceError "
| The operation is not allowed by Namespaces in XML. [XML-NAMES] | NAMESPACE_ERR (14)
|
"InvalidAccessError "
| Deprecated. Use TypeError for invalid arguments,
"NotSupportedError " DOMException for unsupported operations, and
"NotAllowedError " DOMException for denied requests instead.
| INVALID_ACCESS_ERR (15)
|
"TypeMismatchError "
| Deprecated. Use TypeError instead.
| TYPE_MISMATCH_ERR (17)
|
"SecurityError "
| The operation is insecure. | SECURITY_ERR (18)
|
"NetworkError "
| A network error occurred. | NETWORK_ERR (19)
|
"AbortError "
| The operation was aborted. | ABORT_ERR (20)
|
"URLMismatchError "
| Deprecated. | URL_MISMATCH_ERR (21)
|
"QuotaExceededError "
| The quota has been exceeded. | QUOTA_EXCEEDED_ERR (22)
|
"TimeoutError "
| The operation timed out. | TIMEOUT_ERR (23)
|
"InvalidNodeTypeError "
| The supplied node is incorrect or has an incorrect ancestor for this operation. [DOM] | INVALID_NODE_TYPE_ERR (24)
|
"DataCloneError "
| The object can not be cloned. | DATA_CLONE_ERR (25)
|
"EncodingError "
| The encoding operation (either encoded or decoding) failed. | — |
"NotReadableError "
| The I/O read operation failed. | — |
"UnknownError "
| The operation failed for an unknown transient reason (e.g. out of memory). | — |
"ConstraintError "
| A mutation operation in a transaction failed because a constraint was not satisfied. [INDEXEDDB] | — |
"DataError "
| Provided data is inadequate. | — |
"TransactionInactiveError "
| A request was placed against a transaction which is currently not active, or which is finished. [INDEXEDDB] | — |
"ReadOnlyError "
| The mutating operation was attempted in a "readonly" transaction. [INDEXEDDB] | — |
"VersionError "
| An attempt was made to open a database using a lower version than the existing version. [INDEXEDDB] | — |
"OperationError "
| The operation failed for an operation-specific reason. | — |
"NotAllowedError "
| The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission. | — |
"OptOutError "
| The user opted out of the process. | — |
2.8.2. DOMException
derived interfaces
When an exception needs to carry additional programmatically-introspectable information, beyond what
can be provided with a DOMException
's name, specification authors can create an interface which inherits from DOMException
. Such interfaces need to follow
certain rules, in order to have a predictable shape for developers. Specifically:
-
The identifier of the interface must end with
Error
, and must not be any of the names in theDOMException
names table. -
The interface must have a constructor operation which sets the instance’s name to the interface’s identifier.
-
Their constructor operation must take as its first parameter an optional
DOMString
named message defaulting to the empty string, and must set the instance’s message to message. -
Their constructor operation should take as its second parameter a dictionary containing the additional information that needs to be exposed.
-
They should have read only attributes, whose names are the same as the members of the constructor dictionary, which return the values accepted by the constructor operation.
-
They should be serializable objects, whose serialization steps and deserialization steps preserve the additional information.
These requirements mean that the inherited code
property of these
interfaces will always return 0.
DOMException
derived interface which carries along an additional
"protocol error code", which is derived from what the server sent over some some hypothetical
network protocol "protocol X", could look something like this:
[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 ; };
Every ProtocolXError
instance has an error code,
a number.
new ProtocolXError(message, options)
constructor steps are:
ProtocolXError
objects are serializable objects.
-
Run the
DOMException
serialization steps given value and serialized. -
Set serialized.[[ErrorCode]] to value’s error code.
-
Run the
DOMException
deserialization steps given serialized and value. -
Set value’s error code to serialized.[[ErrorCode]].
To create or throw a DOMException
derived interface, supply its interface identifier as well as the additional information needed to construct it.
To throw an instance of the ProtocolXError
exemplified above:
Throw a
ProtocolXError
whose error code is 42.
2.9. Enumerations
An enumeration is a definition (matching DOMString
values that can be assigned to an attribute or passed to an operation.
enum identifier {"enum" ,"values" /* , ... */ };
The enumeration values are specified
as a comma-separated list of
It is strongly suggested that enumeration values be all lowercase,
and that multiple words be separated using dashes or not be
separated at all, unless there is a specific reason to use another
value naming scheme. For example, an enumeration value that
indicates an object should be created could be named
"createobject
" or "create-object
".
Consider related uses of enumeration values when deciding whether
to dash-separate or not separate enumeration value words so that
similar APIs are consistent.
The behavior when a string value that is not a valid enumeration value is used when assigning to an attribute, or passed as an operation argument, whose type is the enumeration, is language binding specific.
Note: In the JavaScript binding, assignment of an invalid string value to an attribute is ignored, while passing such a value in other contexts (for example as an operation argument) results in an exception being thrown.
No extended attributes defined in this specification are applicable to enumerations.
Enum ::enum identifier { EnumValueList } ;
EnumValueList ::string EnumValueListComma
EnumValueListComma ::, EnumValueListString ε
EnumValueListString ::string EnumValueListComma ε
The following IDL fragment defines an enumeration that is used as the type of an attribute and an operation argument:
enum MealType {"rice" ,"noodles" ,"other" }; [Exposed =Window ]interface Meal {attribute MealType type ;attribute double size ; // in gramsundefined initialize (MealType type ,double size ); };
A JavaScript implementation would restrict the strings that can be assigned to the type property or passed to the initializeMeal function to those identified in the enumeration.
var meal= getMeal(); // Get an instance of Meal. meal. initialize( "rice" , 200 ); // Operation invoked as normal. try { meal. initialize( "sandwich" , 100 ); // Throws a TypeError. } catch ( e) { } meal. type= "noodles" ; // Attribute assigned as normal. meal. type= "dumplings" ; // Attribute assignment ignored. meal. type== "noodles" ; // Evaluates to true.
2.10. Callback functions
The “Custom DOM Elements” spec wants to use callback function types for platform object provided functions. Should we rename “callback functions” to just “functions” to make it clear that they can be used for both purposes?
A callback function is a definition (matching
callback identifier =return_type (/* arguments... */);
Note: See also the similarly named callback interfaces.
The identifier on the
left of the equals sign gives the name of the callback function and the return type and argument list (matching
Callback functions must not be used as the type of a constant.
The following extended attribute is applicable to callback functions:
[LegacyTreatNonObjectAsNull
].
CallbackOrInterfaceOrMixin ::callback CallbackRestOrInterface interface InterfaceOrMixin
CallbackRest ::identifier = Type ( ArgumentList ) ;
The following IDL fragment defines a callback function used for an API that invokes a user-defined function when an operation is complete.
callback AsyncOperationCallback =undefined (DOMString status ); [Exposed =Window ]interface AsyncOperations {undefined performOperation (AsyncOperationCallback whenFinished ); };
In the JavaScript language binding, a function object is passed as the operation argument.
var ops= getAsyncOperations(); // Get an instance of AsyncOperations. ops. performOperation( function ( status) { window. alert( "Operation finished, status is " + status+ "." ); });
2.11. Typedefs
A typedef is a definition (matching
typedef type identifier ;
The type being given a new name is specified after the
The
No extended attributes defined in this specification are applicable to typedefs.
Typedef ::typedef TypeWithExtendedAttributes identifier ;
The following IDL fragment demonstrates the use of typedefs to allow the use of a short identifier instead of a long sequence type.
[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. Objects implementing interfaces
In a given implementation of a set of IDL fragments, an object can be described as being a platform object.
Platform objects are objects that implement an interface.
Legacy platform objects are platform objects that implement an interface which
does not have a [Global
] extended attribute, and which supports indexed properties, named properties, or both.
In a browser, for example,
the browser-implemented DOM objects (implementing interfaces such as Node
and Document
) that provide access to a web page’s contents
to JavaScript running in the page would be platform objects. These objects might be exotic objects,
implemented in a language like C++, or they might be native JavaScript objects. Regardless,
an implementation of a given set of IDL fragments needs to be able to recognize all platform objects that are created by the implementation. This might be done by having some internal state that records whether
a given object is indeed a platform object for that implementation, or perhaps by observing
that the object is implemented by a given internal C++ class. How exactly platform objects
are recognized by a given implementation of a set of IDL fragments is implementation specific.
All other objects in the system would not be treated as platform objects. For example, assume that
a web page opened in a browser loads a JavaScript library that implements DOM Core. This library
would be considered to be a different implementation from the browser provided implementation.
The objects created by the JavaScript library that implement the Node
interface
will not be treated as platform objects that implement Node
by the browser implementation.
Callback interfaces, on the other hand, can be implemented by any JavaScript object. This
allows Web APIs to invoke author-defined operations. For example, the DOM Events implementation
allows authors to register callbacks by providing objects that implement the EventListener
interface.
2.13. Types
This section lists the types supported by Web IDL, the set of values or Infra type corresponding to each type, and how constants of that type are represented.
The following types are known as integer types: byte
, octet
, short
, unsigned short
, long
, unsigned long
, long long
and unsigned long long
.
The following types are known as numeric types:
the integer types, float
, unrestricted float
, double
and unrestricted double
.
The primitive types are bigint
, boolean
and the numeric types.
The string types are DOMString
, all enumeration types, ByteString
and USVString
.
The buffer types are ArrayBuffer
and SharedArrayBuffer
.
The typed array types are Int8Array
, Int16Array
, Int32Array
, Uint8Array
, Uint16Array
, Uint32Array
, Uint8ClampedArray
, BigInt64Array
, BigUint64Array
, Float16Array
, Float32Array
, and Float64Array
.
The buffer view types are DataView
and the typed array types.
The buffer source types are the buffer types and the buffer view types.
The object
type,
all interface types, and
all callback interface types are known as object types.
When conversions are made from language binding specific types to IDL types in order to invoke an operation or assign a value to an attribute, all conversions necessary will be performed before the specified functionality of the operation or attribute assignment is carried out. If the conversion cannot be performed, then the operation will not run or the attribute will not be updated. In some language bindings, type conversions could result in an exception being thrown. In such cases, these exceptions will be propagated to the code that made the attempt to invoke the operation or assign to the attribute.
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 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
The any
type is the union of all other possible
non-union types.
The any
type is like
a discriminated union type, in that each of its values has a
specific non-any
type
associated with it. For example, one value of the any
type is the unsigned long
150, while another is the long
150.
These are distinct values.
The particular type of an any
value is known as its specific type.
(Values of union types also have specific types.)
2.13.2. undefined
The undefined
type has a unique value.
undefined
constant values in IDL
are represented with the
undefined
must not be used as the type of an argument in any circumstance
(in an operation, callback function, constructor operation, etc),
or as the type of a dictionary member,
whether directly or in a union.
Instead, use an optional argument or a non-required dictionary member.
Note: This value was previously spelled void
,
and more limited in how it was allowed to be used.
2.13.3. boolean
The boolean
type has two values: true
and false
.
boolean
constant values in IDL are
represented with the
2.13.4. byte
The byte
type is a signed integer
type that has values in the range [−128, 127].
byte
constant values in IDL are
represented with
2.13.5. octet
The octet
type is an unsigned integer
type that has values in the range [0, 255].
octet
constant values in IDL are
represented with
2.13.6. short
The short
type is a signed integer
type that has values in the range [−32768, 32767].
short
constant values in IDL are
represented with
2.13.7. unsigned short
The unsigned short
type is an unsigned integer
type that has values in the range [0, 65535].
unsigned short
constant values in IDL are
represented with
2.13.8. long
The long
type is a signed integer
type that has values in the range [−2147483648, 2147483647].
long
constant values in IDL are
represented with
2.13.9. unsigned long
The unsigned long
type is an unsigned integer
type that has values in the range [0, 4294967295].
unsigned long
constant values in IDL are
represented with
2.13.10. long long
The long long
type is a signed integer
type that has values in the range [−9223372036854775808, 9223372036854775807].
long long
constant values in IDL are
represented with
2.13.11. unsigned long long
The unsigned long long
type is an unsigned integer
type that has values in the range [0, 18446744073709551615].
unsigned long long
constant values in IDL are
represented with
2.13.12. float
The float
type is a floating point numeric
type that corresponds to the set of finite single-precision 32-bit
IEEE 754 floating point numbers. [IEEE-754]
float
constant values in IDL are
represented with
Unless there are specific reasons to use a 32-bit floating point type,
specifications should use double
rather than float
,
since the set of values that a double
can
represent more closely matches a JavaScript Number.
2.13.13. unrestricted float
The unrestricted float
type is a floating point numeric
type that corresponds to the set of all possible single-precision 32-bit
IEEE 754 floating point numbers, finite, non-finite, and special "not a number" values (NaNs). [IEEE-754]
unrestricted float
constant values in IDL are
represented with
2.13.14. double
The double
type is a floating point numeric
type that corresponds to the set of finite double-precision 64-bit
IEEE 754 floating point numbers. [IEEE-754]
double
constant values in IDL are
represented with
2.13.15. unrestricted double
The unrestricted double
type is a floating point numeric
type that corresponds to the set of all possible double-precision 64-bit
IEEE 754 floating point numbers, finite, non-finite, and special "not a number" values (NaNs). [IEEE-754]
unrestricted double
constant values in IDL are
represented with
2.13.16. bigint
The bigint
type is an arbitrary integer type, unrestricted in range.
bigint
constant values in IDL are represented with
2.13.17. DOMString
The DOMString
type corresponds to strings.
Note: DOMString
. To allow DOMString
, written as DOMString?
in IDL, needs to be used.
Note: A DOMString
value might include unmatched surrogate code points. Use USVString
if this is not desirable.
There is no way to represent a constant DOMString
value in IDL, although DOMString
dictionary member default values and operation optional argument default values can be set to the value of a
2.13.18. ByteString
The ByteString
type corresponds to byte sequences.
There is no way to represent a constant ByteString
value in IDL, although ByteString
dictionary member default values and operation optional argument default values can be set to the value of a
Specifications should only use ByteString
for interfacing with protocols
that use bytes and strings interchangeably, such as HTTP. In general,
strings should be represented with DOMString
values, even if it is expected
that values of the string will always be in ASCII or some
8-bit character encoding. Sequences or frozen arrays with octet
or byte
elements, Uint8Array
, or Int8Array
should be used for holding
8-bit data rather than ByteString
.
2.13.19. USVString
The USVString
type
corresponds to scalar value strings.
Depending on the context,
these can be treated as sequences of either 16-bit unsigned integer code units or scalar values.
There is no way to represent a constant USVString
value in IDL, although USVString
dictionary member default values and operation optional argument default values can be set to the value of a
Specifications should only use USVString
for APIs that perform
text processing and need a string of scalar values to operate on. Most APIs that use strings
should instead be using DOMString
,
which does not make any interpretations of the code units in the string. When in doubt, use DOMString
.
2.13.20. object
The object
type corresponds to the set of
all possible non-null object references.
There is no way to represent a constant object
value in IDL.
To denote a type that includes all possible object references plus the object?
.
2.13.21. symbol
The symbol
type corresponds to the set of all possible symbol values. Symbol values are opaque,
non-object
values which nevertheless have identity (i.e., are only equal to themselves).
There is no way to represent a constant symbol
value in IDL.
2.13.22. Interface types
An identifier that identifies an interface is used to refer to a type that corresponds to the set of all possible non-null references to objects that implement that interface.
An IDL value of the interface type is represented just by an object reference.
There is no way to represent a constant object reference value for a particular interface type in IDL.
To denote a type that includes all possible references to objects implementing
the given interface plus the
2.13.23. Callback interface types
An identifier that identifies a callback interface is used to refer to a type that corresponds to the set of all possible non-null references to objects.
An IDL value of the interface type is represented by a tuple of an object reference and a callback context. The callback context is a language binding specific value, and is used to store information about the execution context at the time the language binding specific object reference is converted to an IDL value.
Note: For JavaScript objects, the callback context is used to hold a reference to the incumbent settings object at the time the Object value is converted to an IDL callback interface type value. See § 3.2.16 Callback interface types.
There is no way to represent a constant object reference value for a particular callback interface type in IDL.
To denote a type that includes all possible references to objects plus the
2.13.24. Dictionary types
An identifier that identifies a dictionary is used to refer to a type that corresponds to the set of all dictionaries that adhere to the dictionary definition.
The literal syntax for ordered maps may also be used to represent dictionaries, when it is implicitly understood from context that the map is being treated as an instance of a specific dictionary type. However, there is no way to represent a constant dictionary value inside IDL fragments.
2.13.25. Enumeration types
An identifier that
identifies an enumeration is used to
refer to a type whose values are the set of strings (sequences of code units, as with DOMString
) that are the enumeration’s values.
Like DOMString
, there is no way to represent a constant enumeration value in IDL, although enumeration-typed dictionary member default values and operation optional argument default values can be set to the value of a
2.13.26. Callback function types
An identifier that identifies a callback function is used to refer to a type whose values are references to objects that are functions with the given signature.
Note: If the [LegacyTreatNonObjectAsNull
] extended attribute is specified on the definition of
the callback function, the values can be references to objects that are not functions.
An IDL value of the callback function type is represented by a tuple of an object reference and a callback context.
Note: As with callback interface types, the callback context is used to hold a reference to the incumbent settings object at the time a JavaScript Object value is converted to an IDL callback function type value. See § 3.2.19 Callback function types.
There is no way to represent a constant callback function value in IDL.
2.13.27. Nullable types — T?
A nullable type is an IDL type constructed
from an existing type (called the inner type),
which just allows the additional value
-
any
, -
a promise type,
-
another nullable type, or
-
a union type that itself includes a nullable type or has a dictionary type as one of its flattened member types.
Note: Although dictionary types can in general be nullable, they cannot when used as the type of an operation argument or a dictionary member.
Nullable type constant values in IDL are represented in the same way that
constant values of their inner type would be represented, or with the
For example, a type that allows the values boolean?
:
[Exposed =Window ]interface NetworkFetcher {undefined get (optional boolean ?areWeThereYet =false ); };
The following interface has two attributes: one whose value can
be a DOMString
or the Node
object or the
[Exposed =Window ]interface Node {readonly attribute DOMString ?namespaceURI ;readonly attribute Node ?parentNode ; // ... };
2.13.28. Sequence types — sequence<T>
The sequence<T> type is a parameterized type whose values are (possibly zero-length) lists of values of type T.
Sequences are always passed by value. In language bindings where a sequence is represented by an object of some kind, passing a sequence to a platform object will not result in a reference to the sequence being kept by that object. Similarly, any sequence returned from a platform object will be a copy and modifications made to it will not be visible to the platform object.
The literal syntax for lists may also be used to represent sequences, when it is implicitly understood from context that the list is being treated as a sequences. However, there is no way to represent a constant sequence value inside IDL fragments.
Sequences must not be used as the type of an attribute or constant.
Note: This restriction exists so that it is clear to specification writers and API users that sequences are copied rather than having references to them passed around. Instead of a writable attribute of a sequence type, it is suggested that a pair of operations to get and set the sequence is used.
Any list can be implicitly treated as a sequence<T>
, as long as it contains
only items that are of type T.
2.13.29. Record types — record<K, V>
A record type is a parameterized type whose values are ordered maps with keys that are instances of K and values that are instances of V. K must be one
of DOMString
, USVString
, or ByteString
.
The literal syntax for ordered maps may also be used to represent records, when it is implicitly understood from context that the map is being treated as a record. However, there is no way to represent a constant record value inside IDL fragments.
Records are always passed by value. In language bindings where a record is represented by an object of some kind, passing a record to a platform object will not result in a reference to the record being kept by that object. Similarly, any record returned from a platform object will be a copy and modifications made to it will not be visible to the platform object.
Records must not be used as the type of an attribute or constant.
Any ordered map can be implicitly treated as a record<K, V>
, as long as
it contains only entries whose keys are all of of type K and whose values are all of type V.
2.13.30. Promise types — Promise<T>
A promise type is a parameterized type whose values are references to objects that “is used as a place holder for the eventual results of a deferred (and possibly asynchronous) computation result of an asynchronous operation”. See section 25.4 of the JavaScript specification for details on the semantics of promise objects.
Promise types are non-nullable, but T may be nullable.
There is no way to represent a promise value in IDL.
2.13.31. Union types
A union type is a type whose set of values
is the union of those in two or more other types. Union types (matching
For example, you might write (Node or DOMString)
or (double or sequence<double>)
. When applying a (Node or DOMString)?
.
Note that the member types of a union type do not descend into nested union types. So for (double or (sequence<long> or Event) or (Node or DOMString)?)
the member types
are double
, (sequence<long> or Event)
and (Node or DOMString)?
.
Like the any
type, values of
union types have a specific type,
which is the particular member type that matches the value.
The flattened member types of a union type, possibly annotated, is a set of types determined as follows:
-
Let T be the union type.
-
Initialize S to ∅.
-
For each member type U of T:
-
If U is an annotated type, then set U to be the inner type of U.
-
If U is a nullable type, then set U to be the inner type of U.
-
If U is a union type, then add to S the flattened member types of U.
-
Otherwise, U is not a union type. Add U to S.
-
-
Return S.
Note: For example, the flattened member types of the union type (Node or (sequence<long> or Event) or (XMLHttpRequest or DOMString)? or sequence<(sequence<double> or NodeList)>)
are the six types Node
, sequence<long>
, Event
, XMLHttpRequest
, DOMString
and sequence<(sequence<double> or NodeList)>
.
The number of nullable member types of a union type is an integer determined as follows:
-
Let T be the union type.
-
Initialize n to 0.
-
For each member type U of T:
-
If U is a nullable type, then:
-
Set n to n + 1.
-
Set U to be the inner type of U.
-
-
If U is a union type, then:
-
Let m be the number of nullable member types of U.
-
Set n to n + m.
-
-
-
Return n.
The any
type must not
be used as a union member type.
The number of nullable member types of a union type must be 0 or 1, and if it is 1 then the union type must also not have a dictionary type in its flattened member types.
A type includes a nullable type if:
-
the type is a nullable type, or
-
the type is an annotated type and its inner type is a nullable type, or
-
the type is a union type and its number of nullable member types is 1.
Each pair of flattened member types in a union type, T and U, must be distinguishable.
It is possible to create a union of bigint
and a numeric type.
However, this is generally only supposed to be used for interfaces such as NumberFormat, which formats the values rather than using them in
calculations.
It would not be appropriate to accept such a union, only to then convert values of the numeric type to a bigint
for further processing, as this runs the risk of introducing
precision errors.
Please file an issue before using this feature.
A type includes undefined if:
-
the type is
undefined
, or -
the type is a nullable type and its inner type includes undefined, or
-
the type is an annotated type and its inner type includes undefined, or
-
the type is a union type and one of its member types includes undefined.
Union type constant values in IDL are represented in the same way that constant values of their member types would be represented.
DistinguishableType ::PrimitiveType Null StringType Null identifier Null sequence < TypeWithExtendedAttributes > Null object Null symbol Null BufferRelatedType Null FrozenArray < TypeWithExtendedAttributes > Null ObservableArray < TypeWithExtendedAttributes > Null RecordType Null undefined Null
2.13.32. Annotated types
Additional types can be created from existing ones by specifying certain extended attributes on the existing types. Such types are called annotated types, and the types they annotate are called inner types.
[Clamp] long
defines a new annotated type, whose behavior is based on that of
the inner type long
, but modified as specified by the [Clamp
]
extended attribute. The following extended attributes are applicable to types:
[AllowResizable
],
[AllowShared
],
[Clamp
],
[EnforceRange
], and
[LegacyNullToEmptyString
].
-
Let extended attributes be a new empty set.
-
If type appears as part of a
TypeWithExtendedAttributes production, append each of the extended attributes present in the production’sExtendedAttributeList to extended attributes. -
If type is a member type of a union type U, append each of the extended attributes associated with U to extended attributes.
-
If type appears as part of a
Type production directly within anArgument production, append to extended attributes all of the extended attributes present in the production’sExtendedAttributeList that are applicable to types.[
Exposed =Window ]interface I {undefined f ([XAttr ]long attrib ); };Note that this is an example of this step only if [
XAttr
] is applicable to types; otherwise [XAttr
] applies to the argument, and not the argument’s type. -
If type appears as part of a
Type production directly within aDictionaryMember production, append to extended attributes all of the extended attributes present in the production’sExtendedAttributeList that are applicable to types.dictionary D { [XAttr ]long member ; };Note that this is an example of this step only if [
XAttr
] is applicable to types; otherwise [XAttr
] applies to the dictionary member, and not the member’s type. -
If type is a typedef, append the extended attributes associated with the type being given a new name to extended attributes.
-
Return extended attributes.
For any type, the extended attributes associated with it must only contain extended attributes that are applicable to types.
2.13.33. Buffer source types
There are a number of types that correspond to sets of all possible non-null references to objects that represent a buffer of data or a view on to a buffer of data. The table below lists these types and the kind of buffer or view they represent.
Type | Kind of buffer |
---|---|
ArrayBuffer
| An object that holds a pointer (which can be null) to a buffer of a fixed number of bytes |
SharedArrayBuffer
| An object that holds a pointer (which cannot be null) to a shared buffer of a fixed number of bytes |
DataView
| A view on to a buffer type instance that allows typed access to integers and floating point values stored at arbitrary offsets into the buffer |
Int8Array
| A view on to a buffer type instance that exposes it as an array of two’s complement signed integers of the given size in bits |
Int16Array
| |
Int32Array
| |
BigInt64Array
| |
Uint8Array
| A view on to a buffer type instance that exposes it as an array of unsigned integers of the given size in bits |
Uint16Array
| |
Uint32Array
| |
BigUint64Array
| |
Uint8ClampedArray
| A view on to a buffer type instance that exposes it as an array of unsigned 8-bit integers with clamped conversions |
Float16Array
| A view on to a buffer type instance that exposes it as an array of IEEE 754 floating point numbers of the given size in bits; Float16Array corresponds to the ECMAScript proposal [PROPOSAL-FLOAT16ARRAY]. |
Float32Array
| |
Float64Array
|
Note: These types all correspond to classes defined in JavaScript.
There is no way to represent a constant value of any of these types in IDL.
At the specification prose level, IDL buffer source types are simply references to objects. To inspect or manipulate the bytes inside the buffer, specification prose needs to use the algorithms in § 3.2.25 Buffer source types.
BufferRelatedType ::ArrayBuffer SharedArrayBuffer DataView Int8Array Int16Array Int32Array Uint8Array Uint16Array Uint32Array Uint8ClampedArray BigInt64Array BigUint64Array Float16Array Float32Array Float64Array
2.13.34. Frozen array types — FrozenArray<T>
A frozen array type is a parameterized type whose values are references to objects that hold a fixed length array of unmodifiable values. The values in the array are of type T.
Frozen array types must only be used as the type of regular attributes or static attributes defined on an interface.
[Exposed =Window ]interface PersonalPreferences {readonly attribute FrozenArray <DOMString >favoriteColors ;attribute FrozenArray <DOMString >favoriteFoods ;undefined randomizeFavoriteColors (); };
The behavior of these attributes could be defined like so:
EachPersonalPreferences
has associated favorite colors, aFrozenArray
<DOMString
>, initially equal to the result of creating a frozen array from « "purple
", "aquamarine
" ».Each
PersonalPreferences
has an associated favorite foods, aFrozenArray
<DOMString
>, initially equal to the result of creating a frozen array from the empty list.The
favoriteColors
getter steps are to return this's favorite colors.The
favoriteFoods
getter steps are to return this's favorite foods.The
favoriteFoods
setter steps are to set this's favorite foods to the given value.The
randomizeFavoriteColors()
method steps are:
Let newFavoriteColors be a list of two strings representing colors, chosen randomly.
Set this's favorite colors to the result of creating a frozen array from newFavoriteColors.
Since FrozenArray<T> values are references, they are unlike sequence types, which are lists of values that are passed by value.
There is no way to represent a constant frozen array value in IDL.
2.13.35. Observable array types — ObservableArray<T>
An observable array type is a parameterized type whose values are references to a combination of a mutable list of objects of type T, as well as behavior to perform when author code modifies the contents of the list.
The parameterized type T must not be a dictionary type, sequence type, record type, or observable array type. However, T may be nullable.
Similar to sequence types and frozen array types, observable array types wrap around JavaScript array types, imposing additional semantics on their usage.
Observable array types must only be used as the type of regular attributes defined on an interface.
For an attribute whose type is an observable array type, specification authors can specify a series of algorithms:
-
set an indexed value, which accepts an IDL value that is about to be set in the observable array, and the index at which it is being set;
-
delete an indexed value, which accepts an IDL value that is about to be removed from the observable array, and the index from which it is being removed.
Both of these algorithms are optional, and if not provided, the default behavior will be to do nothing. Either algorithm may throw an exception, e.g., to reject invalid values.
Note that when JavaScript code sets an existing index to a new value, this will first call the delete an indexed value algorithm to remove the existing value, and then the set an indexed value algorithm with the new value.
Every regular attribute whose type is an observable array type has a backing list, which is a list, initially empty. Specification authors can modify the contents of the backing list, which will automatically be reflected in the contents of the observable array as observed by JavaScript code. Similarly, any modifications by JavaScript code to the contents of the observable array will be reflected back into the backing list, after passing through the set an indexed value and delete an indexed value algorithms.
There is no way to represent a constant observable array value in IDL.
[Exposed =Window ]interface Building {attribute ObservableArray <Employee >employees ; };
The behavior of the attribute could be defined like so:
The set an indexed value algorithm forBuilding
’semployees
attribute, given employee and index, is:
If employee is not allowed to enter the building today, then throw a "
NotAllowedError
"DOMException
.If index is greater than 200, then throw a "
QuotaExceededError
"DOMException
.Put employee to work!
The delete an indexed value algorithm for
Building
’semployees
attribute, given employee and index, is:
Alert security that employee has left the building.
Then, JavaScript code could manipulate the employees
property in
various ways:
// Get an instance of 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 ; // Will throw: building. employees. push( "not an Employee; a string instead" );
All of these manipulations would pass through the above-defined set an indexed value algorithm, potentially throwing if the conditions described there were met. They would also perform the appropriate side effects listed there and in the delete an indexed value algorithm.
Another thing to note about the above code example is how all of the JavaScript array methods
from %Array.prototype%
work on the observable array. Indeed, it fully behaves like an Array
instance:
const normalArray= []; // If building.employees were defined as an indexed property getter interface: normalArray // would contains a single item, building.employees. // // For observable arrays (and frozen arrays): normalArray contains all of the items inside // of building.employees. normalArray. concat( building. employees); // names is a JavaScript Array. const names= building. employees. map( employee=> employee. name); // Passes various brand checks: console. assert( building. employeesinstanceof Array); console. assert( Array. isArray( building. employees)); console. assert( building. employees. constructor === Array); // Even is treated as an array by JSON.stringify! (Note the outer []s.) console. assert( JSON. stringify( building. employees) === `[{}]` );
2.14. Extended attributes
An extended attribute is an annotation
that can appear on definitions,
types as annotated types, interface members, interface mixin members, callback interface members, namespace members, dictionary members,
and operation arguments, and
is used to control how language bindings will handle those constructs.
Extended attributes are specified with an
The
Grammar symbol | Form | Example |
---|---|---|
| takes no arguments | [Replaceable]
|
| takes an argument list | Not currently used; previously used by [Constructor(double x, double y)]
|
| takes a named argument list | [LegacyFactoryFunction=Image(DOMString src)]
|
| takes an identifier | [PutForwards=name]
|
| takes an identifier list | [Exposed=(Window,Worker)]
|
| takes a wildcard | [Exposed=*]
|
This specification defines a number of extended attributes that are applicable to the JavaScript language binding, which are described in § 3.3 Extended attributes. Each extended attribute definition will state which of the above five forms are allowed.
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 binding
This section describes how definitions written with the IDL defined in § 2 Interface definition language correspond to particular constructs in JavaScript, as defined by the ECMAScript Language Specification [ECMA-262].
Unless otherwise specified, objects defined in this section are ordinary objects as described in ECMAScript § 10.1 Ordinary Object Internal Methods and Internal Slots, and if the object is a function object, ECMAScript § 10.3 Built-in Function Objects.
This section may redefine certain internal methods and internal slots of objects. Other specifications may also override the definitions of any internal method or internal slots of a platform object that is an instance of an interface. These objects with changed semantics shall be treated in accordance with the rules for exotic objects.
As overriding internal JavaScript object methods is a low level operation and
can result in objects that behave differently from ordinary objects,
this facility should not be used unless necessary
for security or compatibility. This is currently used to define the HTMLAllCollection
and Location
interfaces. [HTML]
Unless otherwise specified, exotic objects defined in this section and other specifications have the same internal slots as ordinary objects, and all of the internal methods for which alternative definitions are not given are the same as those of ordinary objects.
Unless otherwise specified, the [[Extensible]] internal slot
of objects defined in this section has the value
Unless otherwise specified, the [[Prototype]] internal slot
of objects defined in this section is %Object.prototype%
.
Some objects described in this section are defined to have a class string,
which is the string to include in the string returned from Object.prototype.toString
.
If an object has a class string classString, then the object must,
at the time it is created, have a property whose name is the %Symbol.toStringTag%
symbol
with PropertyDescriptor{[[Writable]]:
Algorithms in this section use the conventions described in ECMAScript § 5.2 Algorithm Conventions, such as the use of steps and substeps, the use of mathematical operations, and so on. This section may also reference abstract operations and notations defined in other parts of ECMA-262.
When an algorithm says to throw a SomethingError
then this means to construct a new JavaScript SomethingError
object in
the current realm and to throw it, just as the algorithms in ECMA-262 do.
Note that algorithm steps can call in to other algorithms and abstract operations and not explicitly handle exceptions that are thrown from them. When an exception is thrown by an algorithm or abstract operation and it is not explicitly handled by the caller, then it is taken to end the algorithm and propagate out to its caller, and so on.
Consider the following algorithm:
Since ToString can throw an exception (for example if passed the object ({ toString: function() { throw 1 } })
), and the exception is
not handled in the above algorithm, if one is thrown then it causes this
algorithm to end and for the exception to propagate out to its caller, if there
is one.
3.1. JavaScript environment
In a JavaScript implementation of a given set of IDL fragments, there will exist a number of JavaScript objects that correspond to definitions in those IDL fragments. These objects are termed the initial objects, and comprise the following:
Each realm must have its own unique set of each of the initial objects, created before control enters any JavaScript execution context associated with the realm, but after the global object for that realm is created. The [[Prototype]]s of all initial objects in a given realm must come from that same realm.
In an HTML user agent, multiple realms can exist when multiple frames or windows are created. Each frame or window will have its own set of initial objects, which the following HTML document demonstrates:
<!DOCTYPE html> < title > Different Realms</ title > < iframe id = a ></ iframe > < script > var iframe= document. getElementById( "a" ); var w= iframe. contentWindow; // The global object in the frame Object== w. Object; // Evaluates to false, per ECMA-262 Node== w. Node; // Evaluates to false iframeinstanceof w. Node; // Evaluates to false iframeinstanceof w. Object; // Evaluates to false iframe. appendChildinstanceof Function; // Evaluates to true iframe. appendChildinstanceof w. Function; // Evaluates to false </ script >
Note: All interfaces define which realms they are exposed in. This allows, for example, realms for Web Workers to expose different sets of supported interfaces from those exposed in realms for Web pages.
Although at the time of this writing the JavaScript specification does not reflect this, every JavaScript object must have an associated realm. The mechanisms for associating objects with realms are, for now, underspecified. However, we note that in the case of platform objects, the associated realm is equal to the object’s relevant realm, and for non-exotic function objects (i.e. not callable proxies, and not bound functions) the associated realm is equal to the value of the function object's [[Realm]] internal slot.
3.2. JavaScript type mapping
This section describes how types in the IDL map to types in JavaScript.
Each sub-section below describes how values of a given IDL type are represented in JavaScript. For each IDL type, it is described how JavaScript values are converted to an IDL value when passed to a platform object expecting that type, and how IDL values of that type are converted to JavaScript values when returned from a platform object.
Note that the sub-sections and algorithms below also apply to annotated types created by applying extended attributes to the types named in their headers.
3.2.1. any
Since the IDL any
type
is the union of all other IDL types, it can correspond to any
JavaScript value type.
A JavaScript value V is converted to an IDL any
value by running the following algorithm:
-
If V is
undefined , then return the uniqueundefined
IDL value. -
If V is
null , then return thenull object?
reference. -
If V is a Boolean, then return the
boolean
value that represents the same truth value. -
If V is a Number, then return the result of converting V to an
unrestricted double
. -
If V is a BigInt, then return the result of converting V to a
bigint
. -
If V is a String, then return the result of converting V to a
DOMString
. -
If V is a Symbol, then return the result of converting V to a
symbol
. -
If V is an Object, then return an IDL
object
value that references V.
An IDL any
value is converted to a JavaScript value according to the rules for converting
the specific type of the IDL any
value
as described in the remainder of this section.
3.2.2. undefined
A JavaScript value V is converted to an IDL undefined
value by
returning the unique undefined
value, ignoring V.
The unique IDL undefined
value is converted to the
JavaScript
3.2.3. boolean
The IDL boolean
value true
is converted to
the JavaScript boolean
value false
is converted to the JavaScript
3.2.4. Integer types
Mathematical operations used in this section, including those defined in ECMAScript § 5.2 Algorithm Conventions, are to be understood as computing exact mathematical results on mathematical real numbers.
In effect, where x is a Number value, “operating on x” is shorthand for “operating on the mathematical real number that represents the same numeric value as x”.
3.2.4.1. byte
A JavaScript value V is converted to an IDL byte
value by running the following algorithm:
-
Let x be ? ConvertToInt(V, 8, "
signed
"). -
Return the IDL
byte
value that represents the same numeric value as x.
The result of converting an IDL byte
value to a JavaScript
value is a Number that represents
the same numeric value as the IDL byte
value.
The Number value will be an integer in the range [−128, 127].
3.2.4.2. octet
A JavaScript value V is converted to an IDL octet
value by running the following algorithm:
-
Let x be ? ConvertToInt(V, 8, "
unsigned
"). -
Return the IDL
octet
value that represents the same numeric value as x.
The result of converting an IDL octet
value to a JavaScript
value is a Number that represents
the same numeric value as the IDL octet
value.
The Number value will be an integer in the range [0, 255].
3.2.4.3. short
A JavaScript value V is converted to an IDL short
value by running the following algorithm:
-
Let x be ? ConvertToInt(V, 16, "
signed
"). -
Return the IDL
short
value that represents the same numeric value as x.
The result of converting an IDL short
value to a JavaScript
value is a Number that represents the
same numeric value as the IDL short
value.
The Number value will be an integer in the range [−32768, 32767].
3.2.4.4. unsigned short
A JavaScript value V is converted to an IDL unsigned short
value by running the following algorithm:
-
Let x be ? ConvertToInt(V, 16, "
unsigned
"). -
Return the IDL
unsigned short
value that represents the same numeric value as x.
The result of converting an IDL unsigned short
value to a JavaScript
value is a Number that
represents the same numeric value as the IDL unsigned short
value.
The Number value will be an integer in the range [0, 65535].
3.2.4.5. long
A JavaScript value V is converted to an IDL long
value by running the following algorithm:
-
Let x be ? ConvertToInt(V, 32, "
signed
"). -
Return the IDL
long
value that represents the same numeric value as x.
The result of converting an IDL long
value to a JavaScript
value is a Number that
represents the same numeric value as the IDL long
value.
The Number value will be an integer in the range [−2147483648, 2147483647].
3.2.4.6. unsigned long
A JavaScript value V is converted to an IDL unsigned long
value by running the following algorithm:
-
Let x be ? ConvertToInt(V, 32, "
unsigned
"). -
Return the IDL
unsigned long
value that represents the same numeric value as x.
The result of converting an IDL unsigned long
value to a JavaScript
value is a Number that
represents the same numeric value as the IDL unsigned long
value.
The Number value will be an integer in the range [0, 4294967295].
3.2.4.7. long long
A JavaScript value V is converted to an IDL long long
value by running the following algorithm:
-
Let x be ? ConvertToInt(V, 64, "
signed
"). -
Return the IDL
long long
value that represents the same numeric value as x.
The result of converting an IDL long long
value to a JavaScript
value is a Number value that
represents the closest numeric value to the long long
,
choosing the numeric value with an even significand if there are
two equally close values.
If the long long
is in the range
[−253 + 1, 253 − 1], then the Number
will be able to represent exactly the same value as the long long
.
3.2.4.8. unsigned long long
A JavaScript value V is converted to an IDL unsigned long long
value by running the following algorithm:
-
Let x be ? ConvertToInt(V, 64, "
unsigned
"). -
Return the IDL
unsigned long long
value that represents the same numeric value as x.
The result of converting an IDL unsigned long long
value to a JavaScript
value is a Number value that
represents the closest numeric value to the unsigned long long
,
choosing the numeric value with an even significand if there are
two equally close values.
If the unsigned long long
is less than or equal to 253 − 1,
then the Number will be able to
represent exactly the same value as the unsigned long long
.
3.2.4.9. Abstract operations
ConvertToInt(V, bitLength, signedness):
-
If bitLength is 64, then:
-
Let upperBound be 253 − 1.
-
If signedness is "
unsigned
", then let lowerBound be 0. -
Otherwise let lowerBound be −253 + 1.
Note: this ensures
long long
types associated with [EnforceRange
] or [Clamp
] extended attributes are representable in JavaScript’s Number type as unambiguous integers.
-
-
Otherwise, if signedness is "
unsigned
", then:-
Let lowerBound be 0.
-
Let upperBound be 2bitLength − 1.
-
-
Otherwise:
-
Let lowerBound be -2bitLength − 1.
-
Let upperBound be 2bitLength − 1 − 1.
-
-
If x is −0, then set x to +0.
-
If the conversion is to an IDL type associated with the [
EnforceRange
] extended attribute, then:-
Set x to IntegerPart(x).
-
If x < lowerBound or x > upperBound, then throw a
TypeError
. -
Return x.
-
If x is not
NaN and the conversion is to an IDL type associated with the [Clamp
] extended attribute, then: -
If x is
NaN , +0, +∞, or −∞, then return +0. -
Set x to IntegerPart(x).
-
Set x to x modulo 2bitLength.
-
If signedness is "
signed
" and x ≥ 2bitLength − 1, then return x − 2bitLength. -
Otherwise, return x.
3.2.5. float
A JavaScript value V is converted to an IDL float
value by running the following algorithm:
-
Let S be the set of finite IEEE 754 single-precision floating point values except −0, but with two special values added: 2128 and −2128.
-
Let y be the number in S that is closest to x, selecting the number with an even significand if there are two equally close values. (The two special values 2128 and −2128 are considered to have even significands for this purpose.)
-
If y is +0 and x is negative, return −0.
-
Return y.
The result of converting an IDL float
value to a JavaScript
value is the Number value that represents the same numeric value as the IDL float
value.
3.2.6. unrestricted float
A JavaScript value V is converted to an IDL unrestricted float
value by running the following algorithm:
-
If x is
NaN , then return the IDLunrestricted float
value that represents the IEEE 754 NaN value with the bit pattern 0x7fc00000 [IEEE-754]. -
Let S be the set of finite IEEE 754 single-precision floating point values except −0, but with two special values added: 2128 and −2128.
-
Let y be the number in S that is closest to x, selecting the number with an even significand if there are two equally close values. (The two special values 2128 and −2128 are considered to have even significands for this purpose.)
-
If y is 2128, return +∞.
-
If y is −2128, return −∞.
-
If y is +0 and x is negative, return −0.
-
Return y.
Note: Since there is only a single JavaScript
The result of converting an IDL unrestricted float
value to a JavaScript
value is a Number:
-
If the IDL
unrestricted float
value is a NaN, then the Number value isNaN . -
Otherwise, the Number value is the one that represents the same numeric value as the IDL
unrestricted float
value.
3.2.7. double
The result of converting an IDL double
value to a JavaScript
value is the Number value that represents the
same numeric value as the IDL double
value.
3.2.8. unrestricted double
A JavaScript value V is converted to an IDL unrestricted double
value by running the following algorithm:
-
If x is
NaN , then return the IDLunrestricted double
value that represents the IEEE 754 NaN value with the bit pattern 0x7ff8000000000000 [IEEE-754]. -
Return the IDL
unrestricted double
value that represents the same numeric value as x.
Note: Since there is only a single JavaScript
The result of converting an IDL unrestricted double
value to a JavaScript
value is a Number:
-
If the IDL
unrestricted double
value is a NaN, then the Number value isNaN . -
Otherwise, the Number value is the one that represents the same numeric value as the IDL
unrestricted double
value.
3.2.9. bigint
The result of converting an IDL bigint
value to a JavaScript value is a BigInt:
A JavaScript value V is converted to an IDL numeric type T or bigint
value by running the following algorithm:
-
If x is a BigInt, then
-
Return the IDL
bigint
value that represents the same numeric value as x.
-
-
Assert: x is a Number.
-
Return the result of converting x to T.
3.2.10. DOMString
A JavaScript value V is converted to an IDL DOMString
value by running the following algorithm:
-
If V is
null and the conversion is to an IDL type associated with the [LegacyNullToEmptyString
] extended attribute, then return theDOMString
value that represents the empty string. -
Return the IDL
DOMString
value that represents the same sequence of code units as the one the JavaScript String value x represents.
The result of converting an IDL DOMString
value to a JavaScript
value is the String
value that represents the same sequence of code units that the
IDL DOMString
represents.
3.2.11. ByteString
A JavaScript value V is converted to an IDL ByteString
value by running the following algorithm:
The result of converting an IDL ByteString
value to a JavaScript
value is a String
value whose length is the length of the ByteString
,
and the value of each element of which is the value
of the corresponding element of the ByteString
.
3.2.12. USVString
A JavaScript value V is converted to an IDL USVString
value by running the following algorithm:
-
Let string be the result of converting V to a
DOMString
. -
Return an IDL
USVString
value that is the result of converting string to a sequence of scalar values.
The result of converting an IDL USVString
value S to a JavaScript
value is S.
3.2.13. object
IDL object
values are represented by JavaScript Object values.
A JavaScript value V is converted to an IDL object
value by running the following algorithm:
-
If V is not an Object, then throw a
TypeError
. -
Return the IDL
object
value that is a reference to the same object as V.
The result of converting an IDL object
value to a JavaScript
value is the Object value that represents a reference to the same object that the
IDL object
represents.
3.2.14. symbol
IDL symbol
values are represented by JavaScript Symbol values.
symbol
value
by running the following algorithm:
-
If V is not a Symbol, then throw a
TypeError
. -
Return the IDL
symbol
value that is a reference to the same symbol as V.
The result of converting an IDL symbol
value to a
JavaScript value is the Symbol value that represents a reference to the same
symbol that the IDL symbol
represents.
3.2.15. Interface types
IDL interface type values are represented by JavaScript Object values (including function objects).
A JavaScript value V is converted to an IDL interface type value by running the following algorithm (where I is the interface):
-
If V implements I, then return the IDL interface type value that represents a reference to that platform object.
The result of converting an IDL interface type value to a JavaScript value is the Object value that represents a reference to the same object that the IDL interface type value represents.
3.2.16. Callback interface types
IDL callback interface type values are represented by JavaScript Object values (including function objects).
A JavaScript value V is converted to an IDL callback interface type value by running the following algorithm:
-
If V is not an Object, then throw a
TypeError
. -
Return the IDL callback interface type value that represents a reference to V, with the incumbent settings object as the callback context.
The result of converting an IDL callback interface type value to a JavaScript value is the Object value that represents a reference to the same object that the IDL callback interface type value represents.
3.2.17. Dictionary types
IDL dictionary type values are represented by JavaScript Object values. Properties on the object (or its prototype chain) correspond to dictionary members.
A JavaScript value jsDict is converted to an IDL dictionary type value by running the following algorithm (where D is the dictionary type):
-
If jsDict is not an Object and jsDict is neither
undefined nornull , then throw aTypeError
. -
Let idlDict be an empty ordered map, representing a dictionary of type D.
-
Let dictionaries be a list consisting of D and all of D’s inherited dictionaries, in order from least to most derived.
-
For each dictionary dictionary in dictionaries, in order:
-
For each dictionary member member declared on dictionary, in lexicographical order:
-
Let key be the identifier of member.
-
If jsDict is either
undefined ornull , then:-
Let jsMemberValue be
undefined .
-
-
Otherwise,
-
If jsMemberValue is not
undefined , then:-
Let idlMemberValue be the result of converting jsMemberValue to an IDL value whose type is the type member is declared to be of.
-
Set idlDict[key] to idlMemberValue.
-
-
Otherwise, if jsMemberValue is
undefined but member has a default value, then:-
Let idlMemberValue be member’s default value.
-
Set idlDict[key] to idlMemberValue.
-
-
Otherwise, if jsMemberValue is
undefined and member is required, then throw aTypeError
.
-
-
-
Return idlDict.
Note: The order that dictionary members are looked up on the JavaScript object are not necessarily the same as the object’s property enumeration order.
An IDL dictionary value V is converted to a JavaScript Object value by running the following algorithm (where D is the dictionary):
-
Let O be OrdinaryObjectCreate(
%Object.prototype%
). -
Let dictionaries be a list consisting of D and all of D’s inherited dictionaries, in order from least to most derived.
-
For each dictionary dictionary in dictionaries, in order:
-
For each dictionary member member declared on dictionary, in lexicographical order:
-
Let key be the identifier of member.
-
If V[key] exists, then:
-
Let idlValue be V[key].
-
Let value be the result of converting idlValue to a JavaScript value.
-
Perform ! CreateDataPropertyOrThrow(O, key, value).
Recall that if member has a default value, then key will always exist in V.
-
-
-
-
Return O.
3.2.18. Enumeration types
IDL enumeration types are represented by JavaScript String values.
A JavaScript value V is converted to an IDL enumeration type value as follows (where E is the enumeration):
-
If S is not one of E’s enumeration values, then throw a
TypeError
. -
Return the enumeration value of type E that is equal to S.
The result of converting an IDL enumeration type value to a JavaScript value is the String value that represents the same sequence of code units as the enumeration value.
3.2.19. Callback function types
IDL callback function types are represented by JavaScript function objects, except in the
[LegacyTreatNonObjectAsNull
] case, when they can be any object.
A JavaScript value V is converted to an IDL callback function type value by running the following algorithm:
-
If the result of calling IsCallable(V) is
false and the conversion to an IDL value is not being performed due to V being assigned to an attribute whose type is a nullable callback function that is annotated with [LegacyTreatNonObjectAsNull
], then throw aTypeError
. -
Return the IDL callback function type value that represents a reference to the same object that V represents, with the incumbent settings object as the callback context.
The result of converting an IDL callback function type value to a JavaScript value is a reference to the same object that the IDL callback function type value represents.
3.2.20. Nullable types — T?
IDL nullable type values are represented
by values of either the JavaScript type corresponding to the inner IDL type, or
the JavaScript
A JavaScript value V is converted to an IDL nullable type T?
value (where T is the inner type) as follows:
-
If V is not an Object, and the conversion to an IDL value is being performed due to V being assigned to an attribute whose type is a nullable callback function that is annotated with [
LegacyTreatNonObjectAsNull
], then return the IDL nullable typeT?
valuenull . -
Otherwise, if V is
undefined , and T includes undefined, return the uniqueundefined
value. -
Otherwise, if V is
null orundefined , then return the IDL nullable typeT?
valuenull . -
Otherwise, return the result of converting V using the rules for the inner IDL type
T
.
The result of converting an IDL nullable type value to a JavaScript value is:
-
If the IDL nullable type
T?
value isnull , then the JavaScript value isnull . -
Otherwise, the JavaScript value is the result of converting the IDL nullable type value to the inner IDL type
T
.
3.2.21. Sequences — sequence<T>
IDL sequence<T> values are represented by JavaScript Array values.
A JavaScript value V is converted to an IDL sequence<T> value as follows:
-
If V is not an Object, throw a
TypeError
. -
Let method be ? GetMethod(V,
%Symbol.iterator%
). -
Return the result of creating a sequence from V and method.
An IDL sequence value S of type sequence<T> is converted to a JavaScript Array object as follows:
-
Let n be the length of S.
-
Let A be a new Array object created as if by the expression
[]
. -
Initialize i to be 0.
-
While i < n:
-
Let V be the value in S at index i.
-
Let E be the result of converting V to a JavaScript value.
-
Perform ! CreateDataPropertyOrThrow(A, P, E).
-
Set i to i + 1.
-
-
Return A.
3.2.21.1. Creating a sequence from an iterable
To create an IDL value of type sequence<T> given an iterable iterable and an iterator getter method, perform the following steps:
-
Let iteratorRecord be ? GetIteratorFromMethod(iterable, method).
-
Initialize i to be 0.
-
Repeat
-
Let next be ? IteratorStepValue(iteratorRecord).
-
If next is
done , then return an IDL sequence value of type sequence<T> of length i, where the value of the element at index j is Sj. -
Initialize Si to the result of converting next to an IDL value of type T.
-
Set i to i + 1.
-
The following interface defines an attribute of a sequence type as well as an operation with an argument of a sequence type.
[Exposed =Window ]interface Canvas {sequence <DOMString >getSupportedImageCodecs ();undefined drawPolygon (sequence <double >coordinates );sequence <double >getLastDrawnPolygon (); // ... };
In a JavaScript implementation of this interface, an Array
object with elements of type String is used to
represent a sequence<DOMString>
, while an
Array with elements of type Number
represents a sequence<double>
. The
Array objects are effectively passed by
value; every time the getSupportedImageCodecs()
function is called a new Array is
returned, and whenever an Array is
passed to drawPolygon
no reference
will be kept after the call completes.
// Obtain an instance of Canvas. Assume that getSupportedImageCodecs() // returns a sequence with two DOMString values: "image/png" and "image/svg+xml". var canvas= getCanvas(); // An Array object of length 2. var supportedImageCodecs= canvas. getSupportedImageCodecs(); // Evaluates to "image/png". supportedImageCodecs[ 0 ]; // Each time canvas.getSupportedImageCodecs() is called, it returns a // new Array object. Thus modifying the returned Array will not // affect the value returned from a subsequent call to the function. supportedImageCodecs[ 0 ] = "image/jpeg" ; // Evaluates to "image/png". canvas. getSupportedImageCodecs()[ 0 ]; // This evaluates to false, since a new Array object is returned each call. canvas. getSupportedImageCodecs() == canvas. getSupportedImageCodecs(); // An Array of Numbers... var a= [ 0 , 0 , 100 , 0 , 50 , 62.5 ]; // ...can be passed to a platform object expecting a sequence<double>. canvas. drawPolygon( a); // Each element will be converted to a double by first calling ToNumber(). // So the following call is equivalent to the previous one, except that // "hi" will be alerted before drawPolygon() returns. a= [ false , "" , { valueOf: function () { alert( "hi" ); return 100 ; } }, 0 , "50" , new Number( 62.5 )]; canvas. drawPolygon( a); // Modifying an Array that was passed to drawPolygon() is guaranteed not to // have an effect on the Canvas, since the Array is effectively passed by value. a[ 4 ] = 20 ; var b= canvas. getLastDrawnPolygon(); alert( b[ 4 ]); // This would alert "50".
3.2.22. Records — record<K, V>
IDL record<K, V> values are represented by JavaScript Object values.
A JavaScript value O is converted to an IDL record<K, V>
value as follows:
-
If O is not an Object, throw a
TypeError
. -
Let result be a new empty instance of
record<K, V>
. -
Let keys be ? O.[[OwnPropertyKeys]]().
-
For each key of keys:
-
Let desc be ? O.[[GetOwnProperty]](key).
-
If desc is not
undefined and desc.[[Enumerable]] istrue :-
Let typedKey be key converted to an IDL value of type K.
-
Let typedValue be value converted to an IDL value of type V.
-
Set result[typedKey] to typedValue.
Note: It’s possible that typedKey is already in result, if K is
USVString
and key contains unpaired surrogates.
-
-
-
Return result.
An IDL record<…>
value D is converted to a JavaScript value as follows:
-
Let result be OrdinaryObjectCreate(
%Object.prototype%
). -
For each key → value of D:
-
Let jsKey be key converted to a JavaScript value.
-
Let jsValue be value converted to a JavaScript value.
-
Let created be ! CreateDataProperty(result, jsKey, jsValue).
-
Assert: created is
true .
-
-
Return result.
Passing the JavaScript value {b: 3, a: 4}
as a record<DOMString, double>
argument
would result in the IDL value «[ "b
" → 3, "a
" → 4 ]».
Records only consider own enumerable properties, so given an IDL operation record<DOMString, double>
identity(record<DOMString, double> arg)
which returns its
argument, the following code passes its assertions:
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 );
Record keys and values can be constrained, although keys can only be constrained among the three string types. The following conversions have the described results:
Value | Passed to type | Result |
---|---|---|
{"😞": 1}
| record<ByteString, double>
| TypeError
|
{"\uD83D": 1}
| record<USVString, double>
| «[ "\uFFFD " → 1 ]»
|
{"\uD83D": {hello: "world"}}
| record<DOMString, double>
| «[ "\uD83D " → 0 ]»
|
3.2.23. Promise types — Promise<T>
IDL promise type values are represented by JavaScript PromiseCapability records.
A JavaScript value V is converted to an IDL Promise<T>
value as follows:
-
Let promiseCapability be ? NewPromiseCapability(
%Promise%
). -
Perform ? Call(promiseCapability.[[Resolve]],
undefined , « V »). -
Return promiseCapability.
The result of converting an IDL promise type value to a JavaScript value is the value of the [[Promise]] field of the record that IDL promise type represents.
3.2.23.1. Creating and manipulating Promises
To create a new Promise<T>
in a realm realm,
perform the following steps:
-
Let constructor be realm.[[Intrinsics]].[[
%Promise%
]]. -
Return ? NewPromiseCapability(constructor).
To create a resolved promise of type Promise<T>
, with x (a value of type T) in a realm realm, perform the following steps:
-
Let value be the result of converting x to a JavaScript value.
-
Let constructor be realm.[[Intrinsics]].[[
%Promise%
]]. -
Let promiseCapability be ? NewPromiseCapability(constructor).
-
Perform ! Call(promiseCapability.[[Resolve]],
undefined , « value »). -
Return promiseCapability.
To create a rejected promise of type Promise<T>
, with reason r (a
JavaScript value) in a realm realm, perform the following steps:
-
Let constructor be realm.[[Intrinsics]].[[
%Promise%
]]. -
Let promiseCapability be ? NewPromiseCapability(constructor).
-
Perform ! Call(promiseCapability.[[Reject]],
undefined , « r »). -
Return promiseCapability.
To resolve a Promise<T>
p with x (a
value of type T), perform the following steps:
-
If x is not given, then let it be the
undefined
value. -
Let value be the result of converting x to a JavaScript value.
If T is undefined
, then the x argument is optional, allowing a simpler "resolve p" usage.
To reject a Promise<T>
p with reason r (a JavaScript value), perform the following steps:
To react to a Promise<T>
promise, given one or two sets of steps
to perform, covering when the promise is fulfilled, rejected, or both, perform the following
steps:
-
Let onFulfilledSteps be the following steps given argument V:
-
Let value be the result of converting V to an IDL value of type T.
-
If there is a set of steps to be run if the promise was fulfilled, then let result be the result of performing them, given value if T is not
undefined
. Otherwise, let result be value. -
Return result, converted to a JavaScript value.
-
-
Let onFulfilled be CreateBuiltinFunction(onFulfilledSteps, « »):
-
Let onRejectedSteps be the following steps given argument R:
-
Let reason be the result of converting R to an IDL value of type
any
. -
If there is a set of steps to be run if the promise was rejected, then let result be the result of performing them, given reason. Otherwise, let result be a promise rejected with reason.
-
Return result, converted to a JavaScript value.
-
-
Let onRejected be CreateBuiltinFunction(onRejectedSteps, « »):
-
Let constructor be promise.[[Promise]].[[Realm]].[[Intrinsics]].[[
%Promise%
]]. -
Let newCapability be ? NewPromiseCapability(constructor).
Note: Not all callers will use the returned
Promise
. Implementations might wish to avoid creating newCapability in those cases. -
Perform PerformPromiseThen(promise.[[Promise]], onFulfilled, onRejected, newCapability).
-
Return newCapability.
Note: This algorithm will behave in a very similar way to the promise.then()
method.
In particular, if the steps return a value of type U or Promise<U>
, this algorithm returns a Promise<U>
as well.
To perform some steps upon fulfillment of a Promise<T>
promise given some steps steps taking a
value of type T, perform the following steps:
-
Return the result of reacting to promise:
-
If promise was fulfilled with value v, then:
-
Perform steps with v.
-
-
To perform some steps upon rejection of a Promise<T>
promise given some steps steps taking a JavaScript value, perform the following steps:
-
Return the result of reacting to promise:
-
If promise was rejected with reason r, then:
-
Perform steps with r.
-
-
To wait for all with a list of Promise<T>
values promises, with success steps successSteps that take a list of T values and failure steps failureSteps that take a
rejection reason any
value, perform the following steps:
-
Let fullfilledCount be 0.
-
Let rejected be false.
-
Let rejectionHandlerSteps be the following steps given arg:
-
If rejected is true, abort these steps.
-
Set rejected to true.
-
Perform failureSteps given arg.
-
-
Let rejectionHandler be CreateBuiltinFunction(rejectionHandlerSteps, « »):
-
Let total be promises’s size.
-
If total is 0, then:
-
Queue a microtask to perform successSteps given « ».
-
Return.
-
-
Let index be 0.
-
Let result be a list containing total null values.
-
For each promise of promises:
-
Let promiseIndex be index.
-
Let fulfillmentHandler be the following steps given arg:
-
Set result[promiseIndex] to arg.
-
Set fullfilledCount to fullfilledCount + 1.
-
If fullfilledCount equals total, then perform successSteps given result.
-
-
Let fulfillmentHandler be CreateBuiltinFunction(fulfillmentHandler, « »):
-
Perform PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler).
-
Set index to index + 1.
-
To get a promise for waiting for all with a list of Promise<T>
values promises and a realm realm, perform the following steps:
-
Let promise be a new promise of type
Promise<sequence<T>>
in realm. -
Let successSteps be the following steps, given results:
-
Resolve promise with results.
-
-
Let failureSteps be the following steps, given reason:
-
Reject promise with reason.
-
-
Wait for all with promises, given successSteps and failureSteps.
-
Return promise.
This definition is useful when you wish to aggregate the results of multiple
promises, and then produce another promise from them, in the same way that Promise.all()
functions for JavaScript code. If you do not need to produce
another promise, then waiting for all is likely better.
Promise<T>
promise, set promise.[[Promise]].[[PromiseIsHandled]] to true.
This definition is useful for promises for which you expect rejections to often
be ignored; it ensures such promises do not cause unhandledrejection
events. The most
common use case is for promise properties, which the web developer might or might not consult.
An example is the writableStreamWriter.closed
promise.
3.2.23.2. Examples
delay
is an operation that returns a promise that will be fulfilled in a
number of milliseconds.
It illustrates how simply you can resolve a promise, with one line of prose.
interface I {Promise <undefined >delay (unrestricted double ms ); };
The delay(ms)
method steps are:
-
Let realm be this's relevant realm.
-
Let taskSource be some appropriate task source.
-
If ms is NaN, let ms be +0; otherwise let ms be the maximum of ms and +0.
-
Let p be a new promise in realm.
-
Run the following steps in parallel:
-
Wait ms milliseconds.
-
Queue a task on taskSource to resolve p.
-
-
Return p.
The validatedDelay
operation is much like the delay
function, except it will validate its arguments.
This shows how to use rejected promises to signal immediate failure before even starting any
asynchronous operations.
interface I {Promise <undefined >validatedDelay (unrestricted double ms ); };
The validatedDelay(ms)
method steps are:
-
Let realm be this's relevant realm.
-
Let taskSource be some appropriate task source.
-
If ms is NaN, return a promise rejected with a
TypeError
in realm. -
If ms < 0, return a promise rejected with a
RangeError
in realm. -
Let p be a new promise in realm.
-
Run the following steps in parallel:
-
Wait ms milliseconds.
-
Queue a task on taskSource to resolve p.
-
-
Return p.
addDelay
is an operation that adds an extra number of milliseconds of delay
between promise settling and the returned promise settling.
interface I {Promise <any >addDelay (Promise <any >promise ,unrestricted double ms ); };
The addDelay(ms, promise)
method steps are:
-
Let realm be this's relevant realm.
-
Let taskSource be some appropriate task source.
-
If ms is NaN, let ms be +0; otherwise let ms be the maximum of ms and +0.
-
Let p be a new promise in realm.
-
React to promise:
-
If promise was fulfilled with value v, then:
-
Run the following steps in parallel:
-
Wait ms milliseconds.
-
Queue a task on taskSource to resolve p with v.
-
-
-
If promise was rejected with reason r, then:
-
Run the following steps in parallel:
-
Wait ms milliseconds.
-
Queue a task on taskSource to reject p with r.
-
-
-
-
Return p.
environment.ready
is an attribute that signals when some part of some
environment, e.g. a DOM document, becomes "ready".
It illustrates how to encode environmental asynchronicity.
interface Environment {readonly attribute Promise <undefined >ready ; };
Every Environment
object must have a ready promise,
which is a Promise<undefined>
.
The ready
attribute getter steps are:
-
Return this's ready promise.
To create an Environment
object in a realm realm, perform the following
steps:
-
Let taskSource be some appropriate task source.
-
Let environment be new
Environment
object in realm. -
Set environment’s ready promise to a new promise in realm.
-
Run the following steps in parallel:
-
Do some asynchronous work.
-
If environment becomes ready successfully, then queue a task on taskSource to resolve environment’s ready promise.
-
If environment fails to become ready, then queue a task on taskSource to reject environment’s ready promise with a "
NetworkError
"DOMException
.
-
-
Return environment.
addBookmark
is an operation that requests that the user add the current web
page as a bookmark.
It’s drawn from some
iterative design work and illustrates a more real-world scenario of appealing to
environmental asynchrony, as well as immediate rejections.
interface I {Promise <undefined >addBookmark (); };
The addBookmark()
method steps are:
-
Let taskSource be some appropriate task source.
-
If this method was not invoked as a result of explicit user action, return a promise rejected with a "
SecurityError
"DOMException
. -
If the document’s mode of operation is standalone, return a promise rejected with a "
NotSupportedError
"DOMException
. -
Let promise be a new promise.
-
Let info be the result of getting a web application’s metadata.
-
Run the following steps in parallel:
-
Using info, and in a manner that is user-agent specific, allow the end user to make a choice as to whether they want to add the bookmark.
-
If the end-user aborts the request to add the bookmark (e.g., they hit escape, or press a "cancel" button), then queue a task on taskSource to reject promise with an "
AbortError
"DOMException
. -
Otherwise, queue a task on taskSource to resolve promise.
-
-
-
Return promise.
Several places in [SERVICE-WORKERS] use get a promise to wait for all. batchRequest
illustrates a simplified version of one of their uses.
It takes as input a sequence of URLs, and returns a promise for a sequence of Response
objects created by fetching the corresponding URL.
If any of the fetches fail, it will return a promise rejected with that failure.
interface I {Promise <sequence <Response >>batchRequest (sequence <USVString >urls ); };
The batchRequest(urls)
method steps are:
-
Let responsePromises be « ».
-
For each url of urls:
-
Let p be the result of getting a promise to wait for all with responsePromises.
-
Return p.
3.2.24. Union types
IDL union type values are represented by JavaScript values that correspond to the union’s member types.
To convert a JavaScript value V to an IDL union type value is done as follows:
-
If the union type includes undefined and V is
undefined , then return the uniqueundefined
value. -
If the union type includes a nullable type and V is
null orundefined , then return the IDL valuenull . -
Let types be the flattened member types of the union type.
-
If V is
null orundefined , then:-
If types includes a dictionary type, then return the result of converting V to that dictionary type.
-
-
If V is a platform object, then:
-
If types includes an interface type that V implements, then return the IDL value that is a reference to the object V.
-
If types includes
object
, then return the IDL value that is a reference to the object V.
-
-
If V is an Object, V has an [[ArrayBufferData]] internal slot, and IsSharedArrayBuffer(V) is false, then:
-
If types includes
ArrayBuffer
, then return the result of converting V toArrayBuffer
. -
If types includes
object
, then return the IDL value that is a reference to the object V.
-
-
If V is an Object, V, has an [[ArrayBufferData]] internal slot, and IsSharedArrayBuffer(V) is true, then:
-
If types includes
SharedArrayBuffer
, then return the result of converting V toSharedArrayBuffer
. -
If types includes
object
, then return the IDL value that is a reference to the object V.
-
-
If V is an Object and V has a [[DataView]] internal slot, then:
-
If types includes
DataView
, then return the result of converting V toDataView
. -
If types includes
object
, then return the IDL value that is a reference to the object V.
-
-
If V is an Object and V has a [[TypedArrayName]] internal slot, then:
-
If types includes a typed array type whose name is the value of V’s [[TypedArrayName]] internal slot, then return the result of converting V to that type.
-
If types includes
object
, then return the IDL value that is a reference to the object V.
-
-
If IsCallable(V) is true, then:
-
If types includes a callback function type, then return the result of converting V to that callback function type.
-
If types includes
object
, then return the IDL value that is a reference to the object V.
-
-
If V is an Object, then:
-
If types includes a sequence type, then
-
Let method be ? GetMethod(V,
%Symbol.iterator%
). -
If method is not
undefined , return the result of creating a sequence of that type from V and method.
-
-
If types includes a frozen array type, then
-
Let method be ? GetMethod(V,
%Symbol.iterator%
). -
If method is not
undefined , return the result of creating a frozen array of that type from V and method.
-
-
If types includes a dictionary type, then return the result of converting V to that dictionary type.
-
If types includes a record type, then return the result of converting V to that record type.
-
If types includes a callback interface type, then return the result of converting V to that callback interface type.
-
If types includes
object
, then return the IDL value that is a reference to the object V.
-
-
If V is a Boolean, then:
-
If types includes
boolean
, then return the result of converting V toboolean
.
-
-
If V is a Number, then:
-
If types includes a numeric type, then return the result of converting V to that numeric type.
-
-
If V is a BigInt, then:
-
If types includes
bigint
, then return the result of converting V tobigint
-
-
If types includes a string type, then return the result of converting V to that type.
-
If types includes a numeric type and
bigint
, then return the result of converting V to either that numeric type orbigint
. -
If types includes a numeric type, then return the result of converting V to that numeric type.
-
If types includes
boolean
, then return the result of converting V toboolean
. -
If types includes
bigint
, then return the result of converting V tobigint
.
An IDL union type value is converted to a JavaScript value according to the rules for converting the specific type of the IDL union type value as described in this section (§ 3.2 JavaScript type mapping).
3.2.25. Buffer source types
A value of an IDL ArrayBuffer
is represented by an object of the corresponding JavaScript class.
If it is not associated with the [AllowResizable
] extended attribute, it can only be backed by JavaScript ArrayBuffer
objects V for which IsResizableArrayBuffer(V) is false.
A value of an IDL SharedArrayBuffer
is represented by an object of the corresponding JavaScript
class. If it is not associated with the [AllowResizable
] extended attribute, it can only be backed by JavaScript SharedArrayBuffer
objects V for which IsResizableArrayBuffer(V) is false.
Values of the IDL buffer view types are represented by objects of the corresponding JavaScript class, with the following additional restrictions on those objects.
- If the type is not associated with either the
[
AllowResizable
] or [AllowShared
] extended attribute, if applicable, they can only be backed by JavaScriptArrayBuffer
objects V for which IsResizableArrayBuffer(V) is false. - If the type is associated with the
[
AllowResizable
] extended attribute but not with the [AllowShared
] extended attribute, if applicable, they can only be backed by JavaScriptArrayBuffer
objects. - If the type is associated with the [
AllowShared
] extended attribute but not with the [AllowResizable
] extended attribute, they can only be backed by JavaScriptArrayBuffer
andSharedArrayBuffer
objects V for which IsResizableArrayBuffer(V) is false. - If the type is associated with both the
[
AllowResizable
] and the [AllowShared
] extended attributes, they can be backed by any JavaScriptArrayBuffer
orSharedArrayBuffer
object.
A JavaScript value V is converted to an IDL ArrayBuffer
value by running the following algorithm:
-
If V is not an Object, or V does not have an [[ArrayBufferData]] internal slot, then throw a
TypeError
. -
If IsSharedArrayBuffer(V) is true, then throw a
TypeError
. -
If the conversion is not to an IDL type associated with the [
AllowResizable
] extended attribute, and IsResizableArrayBuffer(V) is true, then throw aTypeError
. -
Return the IDL
ArrayBuffer
value that is a reference to the same object as V.
A JavaScript value V is converted to an IDL SharedArrayBuffer
value by running the following algorithm:
-
If V is not an Object, or V does not have an [[ArrayBufferData]] internal slot, then throw a
TypeError
. -
If IsSharedArrayBuffer(V) is false, then throw a
TypeError
. -
If the conversion is not to an IDL type associated with the [
AllowResizable
] extended attribute, and IsResizableArrayBuffer(V) is true, then throw aTypeError
. -
Return the IDL
SharedArrayBuffer
value that is a reference to the same object as V.
A JavaScript value V is converted to an IDL DataView
value by running the following algorithm:
-
If V is not an Object, or V does not have a [[DataView]] internal slot, then throw a
TypeError
. -
If the conversion is not to an IDL type associated with the [
AllowShared
] extended attribute, and IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw aTypeError
. -
If the conversion is not to an IDL type associated with the [
AllowResizable
] extended attribute, and IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw aTypeError
. -
Return the IDL
DataView
value that is a reference to the same object as V.
A JavaScript value V is converted to an IDL Int8Array
, Int16Array
, Int32Array
, Uint8Array
, Uint16Array
, Uint32Array
, Uint8ClampedArray
, BigInt64Array
, BigUint64Array
, Float16Array
, Float32Array
, or Float64Array
value
by running the following algorithm:
-
Let T be the IDL type V is being converted to.
-
If V is not an Object, or V does not have a [[TypedArrayName]] internal slot with a value equal to T’s name, then throw a
TypeError
. -
If the conversion is not to an IDL type associated with the [
AllowShared
] extended attribute, and IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw aTypeError
. -
If the conversion is not to an IDL type associated with the [
AllowResizable
] extended attribute, and IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw aTypeError
. -
Return the IDL value of type T that is a reference to the same object as V.
ArrayBuffer
from a byte sequence bytes in a realm realm:
-
Let jsArrayBuffer be ? AllocateArrayBuffer(realm.[[Intrinsics]].[[
%ArrayBuffer%
]], bytes’s length). -
Let arrayBuffer be the result of converting jsArrayBuffer to an IDL value of type
ArrayBuffer
. -
Write bytes into arrayBuffer.
-
Return arrayBuffer.
SharedArrayBuffer
from a byte sequence bytes in a realm realm:
-
Let jsSharedArrayBuffer be ? AllocateSharedArrayBuffer(realm.[[Intrinsics]].[[
%SharedArrayBuffer%
]], bytes’s length). -
Let sharedArrayBuffer be the result of converting jsSharedArrayBuffer to an IDL value of type
SharedArrayBuffer
. -
Write bytes into sharedArrayBuffer.
-
Return sharedArrayBuffer.
ArrayBufferView
types from a byte sequence bytes in a realm realm:
-
Assert: if the type is not
DataView
, then bytes’s length modulo the element size of that type is 0. -
Let arrayBuffer be the result of creating an
ArrayBuffer
from bytes in realm. -
Let jsArrayBuffer be the result of converting arrayBuffer to a JavaScript value.
-
Let constructor be the appropriate constructor from realm.[[Intrinsics]] for the type of
ArrayBufferView
being created. -
Return the result of converting jsView into the given type.
-
Let jsBufferSource be the result of converting bufferSource to a JavaScript value.
-
Let jsArrayBuffer be jsBufferSource.
-
Let offset be 0.
-
Let length be 0.
-
If jsBufferSource has a [[ViewedArrayBuffer]] internal slot, then:
-
Set jsArrayBuffer to jsBufferSource.[[ViewedArrayBuffer]].
-
Set offset to jsBufferSource.[[ByteOffset]].
-
Set length to jsBufferSource.[[ByteLength]].
-
-
Otherwise:
-
Assert: jsBufferSource is an
ArrayBuffer
orSharedArrayBuffer
object. -
Set length to jsBufferSource.[[ArrayBufferByteLength]].
-
-
If IsDetachedBuffer(jsArrayBuffer) is true, then return the empty byte sequence.
-
Let bytes be a new byte sequence of length equal to length.
-
For i in the range offset to offset + length − 1, inclusive, set bytes[i − offset] to GetValueFromBuffer(jsArrayBuffer, i, Uint8, true, Unordered).
-
Return bytes.
-
Let jsBufferSource be the result of converting bufferSource to a JavaScript value.
-
If jsBufferSource has a [[ViewedArrayBuffer]] internal slot, then return jsBufferSource.[[ByteLength]].
-
Return jsBufferSource.[[ArrayBufferByteLength]].
-
If bufferSource is a buffer type instance, then return bufferSource.
-
Let jsBufferView be the result of converting bufferSource to a JavaScript value.
-
Let jsBuffer be jsBufferView.[[ViewedArrayBuffer]].
-
If IsSharedArrayBuffer(jsBuffer) is false, then return the result of converting jsBuffer to an IDL value of type
ArrayBuffer
. -
Return the result of converting jsBuffer to an IDL value of type
SharedArrayBuffer
.
-
Let jsArrayBuffer be the result of converting arrayBuffer to a JavaScript value.
-
Assert: bytes’s length ≤ jsArrayBuffer.[[ArrayBufferByteLength]] − startingOffset.
-
For i in the range startingOffset to startingOffset + bytes’s length − 1, inclusive, perform SetValueInBuffer(jsArrayBuffer, i, Uint8, bytes[i - startingOffset], true, Unordered).
ArrayBufferView
view, optionally given a startingOffset (default 0):
-
Let jsView be the result of converting view to a JavaScript value.
-
Assert: bytes’s length ≤ jsView.[[ByteLength]] − startingOffset.
-
Assert: if view is not a
DataView
, then bytes’s length modulo the element size of view’s type is 0. -
Let arrayBuffer be the result of converting jsView.[[ViewedArrayBuffer]] to an IDL value of type
ArrayBuffer
. -
Write bytes into arrayBuffer with startingOffset set to jsView.[[ByteOffset]] + startingOffset.
SharedArrayBuffer
object is involved.
For the non-shared cases, a more recommended pattern is to transfer the ArrayBuffer
first if possible, to ensure the writes cannot overlap with other modifications,
and then give the new ArrayBuffer
instance to author code as necessary. Alternately, you can get a copy of the bytes held by the buffer source, modify those bytes, and then use them to create a new ArrayBuffer
or ArrayBufferView
to give back to author code.
ArrayBuffer
arrayBuffer:
-
Let jsArrayBuffer be the result of converting arrayBuffer to a JavaScript value.
-
Perform ? DetachArrayBuffer(jsArrayBuffer).
This will throw an exception if jsArrayBuffer has an [[ArrayBufferDetachKey]] that is not undefined, such as is the case
with the value of WebAssembly.Memory
's buffer
attribute. [WASM-JS-API-1]
Detaching a buffer that is already detached is a no-op.
-
Let jsArrayBuffer be the result of converting bufferSource to a JavaScript value.
-
If jsArrayBuffer has a [[ViewedArrayBuffer]] internal slot, then set jsArrayBuffer to jsArrayBuffer.[[ViewedArrayBuffer]].
-
Return IsDetachedBuffer(jsArrayBuffer).
-
Let jsArrayBuffer be the result of converting bufferSource to a JavaScript value.
-
If jsArrayBuffer has a [[ViewedArrayBuffer]] internal slot, then set jsArrayBuffer to jsArrayBuffer.[[ViewedArrayBuffer]].
-
If IsSharedArrayBuffer(jsArrayBuffer) is true, then return false.
-
If IsDetachedBuffer(jsArrayBuffer) is true, then return false.
-
If jsArrayBuffer.[[ArrayBufferDetachKey]] is not
undefined , then return false. -
Return true.
ArrayBuffer
arrayBuffer, optionally
given a realm targetRealm:
-
Let jsArrayBuffer be the result of converting arrayBuffer to a JavaScript value.
-
If IsDetachedBuffer(jsArrayBuffer) is false, then throw a
TypeError
. -
Let arrayBufferData be jsArrayBuffer.[[ArrayBufferData]].
-
Let arrayBufferByteLength be jsArrayBuffer.[[ArrayBufferByteLength]].
-
Perform ? DetachArrayBuffer(jsArrayBuffer).
-
If targetRealm is not given, let targetRealm be the current realm.
-
Let jsTransferred be ? AllocateArrayBuffer(targetRealm.[[Intrinsics]].[[
%ArrayBuffer%
]], 0). -
Set jsTransferred.[[ArrayBufferData]] to arrayBufferData.
-
Set jsTransferred.[[ArrayBufferByteLength]] to arrayBufferByteLength.
-
Return the result of converting jsTransferred to an IDL value of type
ArrayBuffer
.
-
arrayBuffer cannot be detached, for the reasons explained in that algorithm’s definition;
-
arrayBuffer is already detached;
-
Sufficient memory cannot be allocated in realm. Generally this will only be the case if realm is in a different agent cluster than the one in which arrayBuffer was allocated. If they are in the same agent cluster, then implementations will just change the backing pointers to get the same observable results with better performance and no allocations.
3.2.26. Frozen arrays — FrozenArray<T>
Values of frozen array types are represented by frozen JavaScript Array object references.
A JavaScript value V is converted to an IDL FrozenArray<T> value by running the following algorithm:
-
Let values be the result of converting V to IDL type sequence<T>.
-
Return the result of creating a frozen array from values.
To create a frozen array from a sequence of values of type T, follow these steps:
-
Let array be the result of converting the sequence of values of type T to a JavaScript value.
-
Perform ! SetIntegrityLevel(array, "
frozen
"). -
Return array.
The result of converting an IDL FrozenArray<T> value to a JavaScript value is the Object value that represents a reference to the same object that the IDL FrozenArray<T> represents.
3.2.26.1. Creating a frozen array from an iterable
To create an IDL value of type FrozenArray<T> given an iterable iterable and an iterator getter method, perform the following steps:
-
Let values be the result of creating a sequence of type sequence<T> from iterable and method.
-
Return the result of creating a frozen array from values.
3.2.27. Observable arrays — ObservableArray<T>
Values of observable array types are represented by observable array exotic objects.
Instead of the usual conversion algorithms, observable array types have special handling as part of the attribute getter and attribute setter algorithms.
In the JavaScript binding, JavaScript objects that represent platform objects have a backing observable array exotic object for each regular attribute of an observable array type. These are created and managed as part of the define the attributes algorithm.
-
Assert: obj implements an interface with the regular attribute attribute.
-
Let oa be obj’s backing observable array exotic object for attribute.
-
Return oa.[[ProxyHandler]].[[BackingList]].
3.3. Extended attributes
This section defines a number of extended attributes whose presence affects the JavaScript binding.
3.3.1. [AllowResizable]
If the [AllowResizable
] extended attribute appears on a buffer type, it creates a new
IDL type that allows for the respective corresponding JavaScript ArrayBuffer
or SharedArrayBuffer
object to be resizable.
If the [AllowResizable
] extended attribute appears on one of the buffer view types and
the [AllowShared
] extended attribute does not, it creates a new IDL type that allows the
buffer view type to be backed by a JavaScript ArrayBuffer
that is
resizable, instead of only by a fixed-length ArrayBuffer
.
If the [AllowResizable
] extended attribute and the [AllowShared
] extended attribute both appear on one of the buffer view types, it creates a new IDL type that allows the buffer
view type to be additionally backed by a JavaScript SharedArrayBuffer
that is growable.
The [AllowResizable
] extended attribute must take no arguments.
A type that is not a buffer source type must not be associated with the [AllowResizable
] extended attribute.
See the rules for converting JavaScript values to IDL buffer source types in § 3.2.25 Buffer source types for the specific requirements that the use of [AllowResizable
] entails.
See the example in § 3.3.2 [AllowShared] for example usage of both [AllowResizable
] and [AllowShared
].
3.3.2. [AllowShared]
If the [AllowShared
] extended attribute appears on one of the buffer view types, it
creates a new IDL type that allows the object to be backed by an SharedArrayBuffer
instead of
only by an ArrayBuffer
.
The [AllowShared
] extended attribute must take no arguments.
A type that is not a buffer view type must not be associated with the [AllowShared
] extended attribute.
See the rules for converting JavaScript values to IDL buffer view types in § 3.2.25 Buffer source types for the specific requirements that the use of [AllowShared
] entails.
3.3.3. [Clamp]
If the [Clamp
] extended attribute appears on one of the integer types, it creates a new
IDL type such that that when a JavaScript Number is converted to the IDL type,
out-of-range values will be clamped to the range of valid values, rather than using the operators
that use a modulo operation (ToInt32, ToUint32, etc.).
The [Clamp
]
extended attribute must take no arguments.
A type annotated with the [Clamp
] extended attribute must not appear in a read only attribute. A type must not be associated with both the
[Clamp
] and [EnforceRange
] extended attributes. A type that is not an integer type must
not be associated with the [Clamp
] extended attribute.
See the rules for converting JavaScript values to the various IDL integer
types in § 3.2.4 Integer types for the specific requirements that the use of
[Clamp
] entails.
In the following IDL fragment,
two operations are declared that
take three octet
arguments; one uses
the [Clamp
] extended attribute on all three arguments, while the other does not:
[Exposed =Window ]interface GraphicsContext {undefined setColor (octet red ,octet green ,octet blue );undefined setColorClamped ([Clamp ]octet red , [Clamp ]octet green , [Clamp ]octet blue ); };
A call to setColorClamped
with
Number values that are out of range for an octet
are clamped to the range [0, 255].
// Get an instance of GraphicsContext. var context= getGraphicsContext(); // Calling the non-[Clamp] version uses ToUint8 to coerce the Numbers to octets. // This is equivalent to calling setColor(255, 255, 1). context. setColor( - 1 , 255 , 257 ); // Call setColorClamped with some out of range values. // This is equivalent to calling setColorClamped(0, 255, 255). context. setColorClamped( - 1 , 255 , 257 );
3.3.4. [CrossOriginIsolated]
If the [CrossOriginIsolated
] extended attribute appears on an interface, partial interface, interface mixin, partial interface mixin, callback interface, namespace, partial namespace, interface member, interface mixin member, or namespace member,
it indicates that the construct is exposed only within an environment whose cross-origin isolated capability is true. The
[CrossOriginIsolated
] extended attribute must not be used on any other construct.
The [CrossOriginIsolated
] extended attribute must take no arguments.
If [CrossOriginIsolated
] appears on an overloaded operation,
then it must appear on all overloads.
The [CrossOriginIsolated
] extended attribute must not be specified both on
-
an interface member and its interface or partial interface;
-
an interface mixin member and its interface mixin or partial interface mixin;
-
a namespace member and its namespace or partial namespace.
Note: This is because adding the [CrossOriginIsolated
] extended attribute on a member when its containing definition is also annotated with the [CrossOriginIsolated
] extended attribute does not further restrict the exposure of the member.
An interface without the [CrossOriginIsolated
] extended attribute must not inherit from another interface
that does specify [CrossOriginIsolated
].
The following IDL fragment defines an interface with one operation that is executable from all contexts, and two which are executable only from cross-origin isolated contexts.
[Exposed =Window ]interface ExampleFeature { // This call will succeed in all contexts.Promise <Result >calculateNotSoSecretResult (); // This operation will not be exposed to a non-isolated context. In such a context, // there will be no "calculateSecretResult" property on ExampleFeature.prototype. [CrossOriginIsolated ]Promise <Result >calculateSecretResult (); // The same applies here: the attribute will not be exposed to a non-isolated context, // and in such a context there will be no "secretBoolean" property on // ExampleFeature.prototype. [CrossOriginIsolated ]readonly attribute boolean secretBoolean ; }; // HighResolutionTimer will not be exposed in a non-isolated context, nor will its members. // In such a context, there will be no "HighResolutionTimer" property on Window. [Exposed =Window ,CrossOriginIsolated ]interface HighResolutionTimer {DOMHighResTimeStamp getHighResolutionTime (); }; // The interface mixin members defined below will never be exposed in a non-isolated // context, regardless of whether the interface that includes them is. That is, in // non-isolated context, there will be no "snap" property on ExampleFeature.prototype. [CrossOriginIsolated ]interface mixin Snapshotable {Promise <boolean >snap (); };ExampleFeature includes Snapshotable ; // On the other hand, the following interface mixin members will be exposed to a // non-isolated context when included by a host interface that doesn’t have the // [CrossOriginIsolated] extended attribute. That is, in a non-isolated context, there will // be a "log" property on ExampleFeature.prototype.interface mixin Loggable {Promise <boolean >log (); };ExampleFeature includes Loggable ;
3.3.5. [Default]
If the [Default
] extended attribute appears on a regular operation, then it indicates
that the appropriate default method steps must be carried out when the operation is invoked.
The [Default
] extended attribute must take no arguments.
The [Default
] extended attribute must not be used on anything other than a regular operation that has default method steps defined.
As an example, the [Default
] extended attribute is suitable
for use on toJSON
regular operations:
[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 ; };
In the JavaScript language binding, there would exist a toJSON()
method on Animal
, Human
,
and (via inheritance) Dog
objects:
// Get an instance of Human. var alice= getHuman(); // Evaluates to an object like this (notice how "pet" still holds // an instance of Dog at this point): // // { // name: "Alice", // age: 59, // pet: Dog // } alice. toJSON(); // Evaluates to an object like this (notice how "breed" is absent, // as the Dog interface doesn’t use the default toJSON steps): // // { // name: "Tramp", // age: 6 // } alice. pet. toJSON(); // Evaluates to a string like this: // '{"name":"Alice","age":59,"pet":{"name":"Tramp","age":6}}' JSON. stringify( alice);
3.3.6. [EnforceRange]
If the [EnforceRange
] extended attribute appears on one of the integer types, it creates
a new IDL type such that that when a JavaScript Number is converted to the IDL
type, out-of-range values will cause an exception to be thrown, rather than being converted to a
valid value using using the operators that use a modulo operation (ToInt32, ToUint32, etc.).
The Number will be rounded toward zero before being checked against its range.
The [EnforceRange
]
extended attribute must take no arguments.
A type annotated with the [EnforceRange
] extended attribute must not appear in a read only attribute. A type must not be associated with both the [Clamp
] and [EnforceRange
] extended attributes. A type that is not an integer type must not be associated with the
[EnforceRange
] extended attribute.
See the rules for converting JavaScript values to the various IDL integer
types in § 3.2 JavaScript type mapping for the specific requirements that the use of
[EnforceRange
] entails.
In the following IDL fragment,
two operations are declared that
take three octet
arguments; one uses
the [EnforceRange
] extended attribute on all three arguments, while the other does not:
[Exposed =Window ]interface GraphicsContext {undefined setColor (octet red ,octet green ,octet blue );undefined setColorEnforcedRange ([EnforceRange ]octet red , [EnforceRange ]octet green , [EnforceRange ]octet blue ); };
In a JavaScript implementation of the IDL, a call to setColorEnforcedRange with
Number values that are out of range for an octet
will result in an exception being
thrown.
// Get an instance of GraphicsContext. var context= getGraphicsContext(); // Calling the non-[EnforceRange] version uses ToUint8 to coerce the Numbers to octets. // This is equivalent to calling setColor(255, 255, 1). context. setColor( - 1 , 255 , 257 ); // When setColorEnforcedRange is called, Numbers are rounded towards zero. // This is equivalent to calling setColor(0, 255, 255). context. setColorEnforcedRange( - 0.9 , 255 , 255.2 ); // The following will cause a TypeError to be thrown, since even after // rounding the first and third argument values are out of range. context. setColorEnforcedRange( - 1 , 255 , 256 );
3.3.7. [Exposed]
When the [Exposed
] extended attribute appears on
an interface, partial interface, interface mixin, partial interface mixin, callback interface, namespace, partial namespace, or
an individual interface member, interface mixin member, or namespace member,
it indicates that the construct is exposed
on that particular set of global interfaces.
The [Exposed
] extended attribute must either take an identifier, take an identifier list or take a wildcard.
Each of the identifiers mentioned must be a global name of some interface and be unique.
The own exposure set is either a set of identifiers or the special value *
, defined as follows:
- If the [
Exposed
] extended attribute takes an identifier I -
The own exposure set is the set « I ».
- If the [
Exposed
] extended attribute takes an identifier list I -
The own exposure set is the set I.
- If the [
Exposed
] extended attribute takes a wildcard -
The own exposure set is
*
.
[Exposed=*]
is to be used with care.
It is only appropriate when an API does not expose significant new capabilities.
If the API might be restricted or disabled in some environments,
it is preferred to list the globals explicitly.
The exposure set intersection of a construct C and interface-or-null H is defined as follows:
-
Assert: C is an interface member, interface mixin member, namespace member, partial interface, partial interface mixin, partial namespace, or interface mixin.
-
Assert: H is an interface or null.
-
If H is null, return C’s own exposure set.
-
If C’s own exposure set is
*
, return H’s exposure set. -
If H’s exposure set is
*
, return C’s own exposure set. -
Return the intersection of C’s own exposure set and H’s exposure set.
-
Assert: C is an interface, callback interface, namespace, interface member, interface mixin member, or namespace member.
-
Let H be C’s host interface if C is an interface mixin member, or null otherwise.
-
If C is an interface member, interface mixin member, or namespace member, then:
-
If the [
Exposed
] extended attribute is specified on C, return the exposure set intersection of C and H. -
Set C to the interface, partial interface, interface mixin, partial interface mixin, namespace, or partial namespace C is declared on.
-
-
If C is a partial interface, partial interface mixin, or partial namespace, then:
-
If the [
Exposed
] extended attribute is specified on C, return the exposure set intersection of C and H. -
Set C to the original interface, interface mixin, or namespace definition of C.
-
-
If C is an interface mixin, then:
-
Assert: H is not null.
-
If the [
Exposed
] extended attribute is specified on C, return the exposure set intersection of C and H. -
Set C to H.
-
-
Assert: C is an interface, callback interface or namespace.
-
Assert: The [
Exposed
] extended attribute is specified on C. -
Return C’s own exposure set.
If [Exposed
] appears on an overloaded operation,
then it must appear identically on all overloads.
The [Exposed
] extended attribute must not be specified both on
an interface member, interface mixin member, or namespace member, and on
the partial interface, partial interface mixin, or partial namespace definition
the member is declared on.
Note: This is because adding an [Exposed
] extended attribute on a partial interface, partial interface mixin, or partial namespace is shorthand for annotating each of its members.
If [Exposed
] appears on a partial interface or partial namespace,
then the partial’s own exposure set must be a subset of
the exposure set of the partial’s original interface or namespace.
If [Exposed
] appears on an interface or namespace member,
then the member's exposure set must be a subset
of the exposure set of the interface or namespace it is a member of.
If [Exposed
] appears both on a partial interface mixin and its original interface mixin,
then the partial interface mixin's own exposure set must be a subset of the interface mixin's own exposure set.
If [Exposed
] appears both on an interface mixin member and the interface mixin it is a member of,
then the interface mixin members's own exposure set must be a subset of the interface mixin's own exposure set.
If an interface X inherits from another interface Y then the exposure set of X must be a subset of the exposure set of Y.
Note: As an interface mixin can be included by different interfaces,
the exposure set of its members is a function of
the interface that includes them.
If the interface mixin member, partial interface mixin, or interface mixin is annotated with an [Exposed
] extended attribute,
then the interface mixin member's exposure set is the intersection of the relevant construct’s own exposure set with the host interface's exposure set.
Otherwise, it is the host interface's exposure set.
-
If construct’s exposure set is not
*
, and realm.[[GlobalObject]] does not implement an interface that is in construct’s exposure set, then return false. -
If realm’s settings object is not a secure context, and construct is conditionally exposed on [
SecureContext
], then return false. -
If realm’s settings object's cross-origin isolated capability is false, and construct is conditionally exposed on [
CrossOriginIsolated
], then return false. -
Return true.
-
Assert: construct is an interface, callback interface, namespace, interface member, interface mixin member, or namespace member.
-
Let H be construct’s host interface if construct is an interface mixin member, or null otherwise.
-
If construct is an interface member, interface mixin member, or namespace member, then:
-
If the exposure condition extended attribute is specified on construct, then return true.
-
Otherwise, set construct to be the interface, partial interface, interface mixin, partial interface mixin, namespace, or partial namespace construct is declared on.
-
-
If construct is a partial interface, partial interface mixin, or partial namespace, then:
-
If the exposure condition extended attribute is specified on construct, then return true.
-
Otherwise, set construct to be the original interface, interface mixin, or namespace definition of construct.
-
-
If construct is an interface mixin, then:
-
If the exposure condition extended attribute is specified on construct, then return true.
-
Otherwise, set construct to H.
-
-
Assert: construct is an interface, callback interface or namespace.
-
If the exposure condition extended attribute is specified on construct, then return true.
-
Otherwise, return false.
Note: Since it is not possible for the relevant settings object for a JavaScript global object to change whether it is a secure context or cross-origin isolated capability over time, an implementation’s decision to create properties for an interface or interface member can be made once, at the time the initial objects are created.
See § 3.7 Interfaces, § 3.7.5 Constants, § 3.7.6 Attributes, § 3.7.7 Operations, and
for the specific requirements that the use of
[Exposed
] entails.
[Exposed
] is intended to be used to control whether interfaces, callback interfaces, namespaces, or individual interface, mixin or namespace members are available for use in workers, Worklet
, Window
, or any combination of the above.
The following IDL fragment shows how that might be achieved:
[Exposed =Window ,Global =Window ]interface Window { // ... }; // By using the same identifier Worker for both SharedWorkerGlobalScope // and DedicatedWorkerGlobalScope, both can be addressed in an [Exposed] // extended attribute at once. [Exposed =Worker ,Global =Worker ]interface SharedWorkerGlobalScope :WorkerGlobalScope { // ... }; [Exposed =Worker ,Global =Worker ]interface DedicatedWorkerGlobalScope :WorkerGlobalScope { // ... }; // Dimensions is available for use in workers and on the main thread. [Exposed =(Window ,Worker )]interface Dimensions {constructor (double width ,double height );readonly attribute double width ;readonly attribute double height ; }; // WorkerNavigator is only available in workers. Evaluating WorkerNavigator // in the global scope of a worker would give you its interface object, while // doing so on the main thread will give you a ReferenceError. [Exposed =Worker ]interface WorkerNavigator { // ... }; // Node is only available on the main thread. Evaluating Node // in the global scope of a worker would give you a ReferenceError. [Exposed =Window ]interface Node { // ... }; // MathUtils is available for use in workers and on the main thread. [Exposed =(Window ,Worker )]namespace MathUtils {double someComplicatedFunction (double x ,double y ); }; // WorkerUtils is only available in workers. Evaluating WorkerUtils // in the global scope of a worker would give you its namespace object, while // doing so on the main thread will give you a ReferenceError. [Exposed =Worker ]namespace WorkerUtils {undefined setPriority (double x ); }; // NodeUtils is only available in the main thread. Evaluating NodeUtils // in the global scope of a worker would give you a ReferenceError. [Exposed =Window ]namespace NodeUtils {DOMString getAllText (Node node ); };
3.3.8. [Global]
If the [Global
] extended attribute appears on an interface,
it indicates that objects implementing this interface will
be used as the global object in a realm.
The [Global
] extended attribute also defines the global names for the interface:
- If the [
Global
] extended attribute takes an identifier -
« the given identifier »
- If the [
Global
] extended attribute takes an identifier list -
the identifier list
The [Global
] extended attribute must be one of the forms given above.
Note: The global names for the interface are the identifiers that can be used to
reference it in the [Exposed
] extended attribute.
A single name can be shared across multiple different global interfaces,
allowing an interface to more easily use [Exposed
] to expose itself to all of them at once.
For example, "Worker
" is used to refer to several distinct types of threading-related
global interfaces.
For these global interfaces, the structure of the prototype chain and how properties corresponding to interface members will be reflected on the prototype objects will be different from other interfaces. Specifically:
-
Any named properties will be exposed on an object in the prototype chain – the named properties object – rather than on the object itself.
-
Interface members from the interface will correspond to properties on the object itself rather than on interface prototype objects.
All realms have an is global prototype chain mutable boolean, which can be set when the realm is created. Its value can not change during the lifetime of the realm. By default it is set to false.
This allows the ShadowRealm
global to have a mutable prototype.
Placing named properties on an object in the prototype chain is done so that variable declarations and bareword assignments will shadow the named property with a property on the global object itself.
Placing properties corresponding to interface members on the object itself will mean that common feature detection methods like the following will work:
var indexedDB= window. indexedDB|| window. webkitIndexedDB|| window. mozIndexedDB|| window. msIndexedDB; var requestAnimationFrame= window. requestAnimationFrame|| window. mozRequestAnimationFrame|| ...;
Because of the way variable declarations are handled in
JavaScript, the code above would result in the window.indexedDB
and window.requestAnimationFrame
evaluating
to
If the [Global
] extended attributes is
used on an interface, then:
-
The interface must not define a named property setter.
-
The interface must not define indexed property getters or setters.
-
The interface must not define a constructor operation.
-
The interface must not also be declared with the [
LegacyOverrideBuiltIns
] extended attribute. -
The interface must not inherit from another interface with the [
LegacyOverrideBuiltIns
] extended attribute. -
Any other interface must not inherit from it.
If [Global
] is specified on
a partial interface definition, then that partial interface definition must
be the part of the interface definition that defines
the named property getter.
The [Global
] extended attribute must not
be used on an interface that can have more
than one object implementing it in the same realm.
Note: This is because the named properties object, which exposes the named properties, is in the prototype chain, and it would not make sense for more than one object’s named properties to be exposed on an object that all of those objects inherit from.
If an interface is declared with the [Global
] extended attribute, then
there must not be more than one member across
the interface
with the same identifier.
There also must not be more than
one stringifier or more than one iterable declaration, asynchronously iterable declaration, maplike declaration or setlike declaration across those interfaces.
Note: This is because all of the members of the interface get flattened down on to the object that implements the interface.
See § 3.7.4 Named properties object for the specific requirements
that the use of [Global
] entails for named properties,
and § 3.7.5 Constants, § 3.7.6 Attributes and § 3.7.7 Operations for the requirements relating to the location of properties
corresponding to interface members.
The Window
interface exposes frames as properties on the Window
object. Since the Window
object also serves as the
JavaScript global object, variable declarations or assignments to the named properties
will result in them being replaced by the new value. Variable declarations for
attributes will not create a property that replaces the existing one.
[Exposed =Window ,Global =Window ]interface Window {getter any (DOMString name );attribute DOMString name ; // ... };
The following HTML document illustrates how the named properties on the Window
object can be shadowed, and how
the property for an attribute will not be replaced when declaring
a variable of the same name:
<!DOCTYPE html> < title > Variable declarations and assignments on Window</ title > < iframe name = abc ></ iframe > <!-- Shadowing named properties --> < script > window. abc; // Evaluates to the iframe’s Window object. abc= 1 ; // Shadows the named property. window. abc; // Evaluates to 1. </ script > <!-- Preserving properties for IDL attributes --> < script > Window. prototype. def= 2 ; // Places a property on the prototype. window. hasOwnProperty( "length" ); // Evaluates to true. length; // Evaluates to 1. def; // Evaluates to 2. </ script > < script > var length; // Variable declaration leaves existing property. length; // Evaluates to 1. var def; // Variable declaration creates shadowing property. def; // Evaluates to undefined. </ script >
3.3.9. [NewObject]
If the [NewObject
] extended attribute appears on a regular or static operation,
then it indicates that when calling the operation,
a reference to a newly created object
must always be returned.
The [NewObject
]
extended attribute must take no arguments.
The [NewObject
]
extended attribute must not
be used on anything other than a regular or static operation whose return type is an interface type or
a promise type.
As an example, this extended attribute is suitable for use on
the createElement()
operation on the Document
interface,
since a new object is always returned when
it is called. [DOM]
[Exposed =Window ]interface Document :Node { [NewObject ]Element createElement (DOMString localName ); // ... };
3.3.10. [PutForwards]
If the [PutForwards
] extended attribute appears on a read only regular attribute declaration whose type is
an interface type,
it indicates that assigning to the attribute will have specific behavior.
Namely, the assignment is “forwarded” to the attribute (specified by
the extended attribute argument) on the object that is currently
referenced by the attribute being assigned to.
The [PutForwards
] extended
attribute must take an identifier.
Assuming that:
-
A is the attribute on which the [
PutForwards
] extended attribute appears, -
I is the interface on which A is declared,
-
J is the interface type that A is declared to be of, and
-
N is the identifier argument of the extended attribute,
then there must be another attribute B declared on J whose identifier is N. Assignment of a value to the attribute A on an object implementing I will result in that value being assigned to attribute B of the object that A references, instead.
Note that [PutForwards
]-annotated attributes can be
chained. That is, an attribute with the [PutForwards
] extended attribute can refer to an attribute that itself has that extended attribute.
There must not exist a cycle in a
chain of forwarded assignments. A cycle exists if, when following
the chain of forwarded assignments, a particular attribute on
an interface is
encountered more than once.
An attribute with the [PutForwards
]
extended attribute must not also be declared
with the [LegacyLenientSetter
] or
[Replaceable
] extended attributes.
The [PutForwards
]
extended attribute must not be used
on an attribute that
is not read only.
The [PutForwards
] extended attribute
must not be used on a static attribute.
The [PutForwards
] extended attribute
must not be used on an attribute declared on
a namespace.
See the Attributes section for how
[PutForwards
]
is to be implemented.
The following IDL fragment defines interfaces for names and people.
The [PutForwards
] extended
attribute is used on the name
attribute
of the Person
interface to indicate
that assignments to that attribute result in assignments to the full
attribute of the Person
object:
[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 ; };
In the JavaScript binding, this would allow assignments to the name
property:
var p= getPerson(); // Obtain an instance of Person. p. name= 'John Citizen' ; // This statement... p. name. full= 'John Citizen' ; // ...has the same behavior as this one.
3.3.11. [Replaceable]
If the [Replaceable
] extended attribute appears on a read only regular attribute,
it indicates that setting the corresponding property on the platform object will result in
an own property with the same name being created on the object
which has the value being assigned. This property will shadow
the accessor property corresponding to the attribute, which
exists on the interface prototype object.
The [Replaceable
]
extended attribute must take no arguments.
An attribute with the [Replaceable
]
extended attribute must not also be declared
with the [LegacyLenientSetter
] or
[PutForwards
] extended attributes.
The [Replaceable
]
extended attribute must not be used
on an attribute that
is not read only.
The [Replaceable
] extended attribute
must not be used on a static attribute.
The [Replaceable
] extended attribute
must not be used on an attribute declared on
a namespace.
See § 3.7.6 Attributes for the specific requirements that the use of
[Replaceable
] entails.
The following IDL fragment defines an interface with an operation that increments a counter, and an attribute that exposes the counter’s value, which is initially 0:
[Exposed =Window ]interface Counter { [Replaceable ]readonly attribute unsigned long value ;undefined increment (); };
Assigning to the value
property
on a platform object implementing Counter
will shadow the property that corresponds to the attribute:
var counter= getCounter(); // Obtain an instance of Counter. counter. value; // Evaluates to 0. counter. hasOwnProperty( "value" ); // Evaluates to false. Object. getPrototypeOf( counter). hasOwnProperty( "value" ); // Evaluates to true. counter. increment(); counter. increment(); counter. value; // Evaluates to 2. counter. value= 'a' ; // Shadows the property with one that is unrelated // to Counter::value. counter. hasOwnProperty( "value" ); // Evaluates to true. counter. increment(); counter. value; // Evaluates to 'a'. delete counter. value; // Reveals the original property. counter. value; // Evaluates to 3.
3.3.12. [SameObject]
If the [SameObject
] extended attribute appears on a read only attribute, then it
indicates that when getting the value of the attribute on a given
object, the same value must always
be returned.
The [SameObject
]
extended attribute must take no arguments.
The [SameObject
]
extended attribute must not
be used on anything other than a read only attribute whose type is an interface type or object
.
As an example, this extended attribute is suitable for use on
the implementation
attribute on the Document
interface
since the same object is always returned for a given Document
object. [DOM]
[Exposed =Window ]interface Document :Node { [SameObject ]readonly attribute DOMImplementation implementation ; // ... };
3.3.13. [SecureContext]
If the [SecureContext
] extended attribute appears on an interface, partial interface, interface mixin, partial interface mixin, callback interface, namespace, partial namespace, interface member, interface mixin member, or namespace member,
it indicates that the construct is exposed only within a secure context.
The [SecureContext
] extended attribute must not be used
on any other construct.
The [SecureContext
] extended attribute must take no arguments.
If [SecureContext
] appears on an overloaded operation,
then it must appear on all overloads.
The [SecureContext
] extended attribute must not be specified both on
-
an interface member and its interface or partial interface;
-
an interface mixin member and its interface mixin or partial interface mixin;
-
a namespace member and its namespace or partial namespace.
Note: This is because adding the [SecureContext
] extended attribute on a member when
its containing definition is also annotated with the [SecureContext
] extended attribute does not further restrict the exposure of the member.
An interface without the [SecureContext
] extended attribute must not inherit from another interface
that does specify [SecureContext
].
[SecureContext
] must not be specified on a construct is that is conditionally exposed on
[CrossOriginIsolated
]. (Doing so would be redundant, since every environment which is cross-origin isolated is also a secure context.)
The following IDL fragment defines an interface with one operation that is executable from all contexts, and two which are executable only from secure contexts.
[Exposed =Window ]interface ExampleFeature { // This call will succeed in all contexts.Promise <Result >calculateNotSoSecretResult (); // This operation will not be exposed to a non-secure context. In such a context, // there will be no "calculateSecretResult" property on ExampleFeature.prototype. [SecureContext ]Promise <Result >calculateSecretResult (); // The same applies here: the attribute will not be exposed to a non-secure context, // and in a non-secure context there will be no "secretBoolean" property on // ExampleFeature.prototype. [SecureContext ]readonly attribute boolean secretBoolean ; }; // HeartbeatSensor will not be exposed in a non-secure context, nor will its members. // In such a context, there will be no "HeartbeatSensor" property on Window. [Exposed =Window ,SecureContext ]interface HeartbeatSensor {Promise <float >getHeartbeatsPerMinute (); }; // The interface mixin members defined below will never be exposed in a non-secure context, // regardless of whether the interface that includes them is. That is, in a non-secure // context, there will be no "snap" property on ExampleFeature.prototype. [SecureContext ]interface mixin Snapshotable {Promise <boolean >snap (); };ExampleFeature includes Snapshotable ; // On the other hand, the following interface mixin members will be exposed to a non-secure // context when included by a host interface that doesn’t have the [SecureContext] extended // attribute. That is, in a non-secure context, there will be a "log" property on // ExampleFeature.prototype.interface mixin Loggable {Promise <boolean >log (); };ExampleFeature includes Loggable ;
3.3.14. [Unscopable]
If the [Unscopable
] extended attribute appears on a regular attribute or regular operation, it
indicates that an object that implements an interface with the given
interface member will not include its property name in any object
environment record with it as its base object. The result of this is
that bare identifiers matching the property name will not resolve to
the property in a with
statement. This is achieved by
including the property name on the interface prototype object's %Symbol.unscopables%
property’s value.
The [Unscopable
]
extended attribute must take no arguments.
The [Unscopable
]
extended attribute must not appear on
anything other than a regular attribute or regular operation.
The [Unscopable
] extended attribute must not be used on an attribute declared on a namespace.
See § 3.7.3 Interface prototype object for the specific requirements that the use of
[Unscopable
] entails.
For example, with the following IDL:
[Exposed =Window ]interface Thing {undefined f (); [Unscopable ]g (); };
the f
property can be referenced with a bare identifier
in a with
statement but the g
property cannot:
var thing= getThing(); // An instance of Thing with ( thing) { f; // Evaluates to a Function object. g; // Throws a ReferenceError. }
3.4. Legacy extended attributes
This section defines a number of extended attributes whose presence affects the JavaScript binding. Unlike those in § 3.3 Extended attributes, these exist only so that legacy Web platform features can be specified. They should not be used in specifications, unless required to specify the behavior of legacy APIs.
Editors who believe they have a good reason for using these extended attributes are strongly advised to discuss this by filing an issue before proceeding.
3.4.1. [LegacyFactoryFunction]
Instead of using this feature, give your interface a constructor operation.
If the [LegacyFactoryFunction
] extended attribute appears on an interface,
it indicates that the JavaScript global object will have a property with the
specified name whose value is a function that can
create objects that implement the interface.
Multiple [LegacyFactoryFunction
] extended
attributes may appear on a given interface.
The [LegacyFactoryFunction
] extended attribute must take a named argument list.
The LegacyFactoryFunction
]'s identifier.
For each [LegacyFactoryFunction
] extended attribute on the interface,
there will be a way to construct an object that implements the interface by passing the specified arguments to the constructor that is the value of the aforementioned property.
The identifier used for the legacy factory function must not
be the same as that used by a [LegacyFactoryFunction
]
extended attribute on another interface, must not
be the same as an identifier used by a [LegacyWindowAlias
]
extended attribute on this interface or another interface,
must not be the same as an identifier of an interface
that has an interface object,
and must not be one of the reserved identifiers.
The [LegacyFactoryFunction
] and [Global
] extended attributes must not be specified on the
same interface.
See § 3.7.2 Legacy factory functions for details on how legacy factory functions are to be implemented.
The following IDL defines an interface that uses the
[LegacyFactoryFunction
] extended
attribute.
[Exposed =Window ,LegacyFactoryFunction =Audio (DOMString src )]interface HTMLAudioElement :HTMLMediaElement { // ... };
A JavaScript implementation that supports this interface will
allow the construction of HTMLAudioElement
objects using the Audio
function.
typeof Audio; // Evaluates to 'function'. var a2= new Audio( 'a.flac' ); // Creates an HTMLAudioElement using the // one-argument constructor.
As an additional legacy quirk, these factory functions will have a prototype
property equal to the prototype
of the original interface:
console. assert( Audio. prototype=== HTMLAudioElement. prototype);
3.4.2. [LegacyLenientSetter]
If the [LegacyLenientSetter
] extended attribute appears on a read only regular attribute,
it indicates that a no-op setter will be generated for the attribute’s
accessor property. This results in erroneous assignments to the property
in strict mode to be ignored rather than causing an exception to be thrown.
Pages have been observed where authors have attempted to polyfill an IDL attribute
by assigning to the property, but have accidentally done so even if the property exists. In strict
mode, this would cause an exception to be thrown, potentially breaking page. Without
[LegacyLenientSetter
], this could prevent a browser from shipping the feature.
The [LegacyLenientSetter
] extended attribute
must take no arguments.
It must not be used on anything other than
a read only regular attribute.
An attribute with the [LegacyLenientSetter
]
extended attribute must not also be declared
with the [PutForwards
]
or [Replaceable
] extended attributes.
The [LegacyLenientSetter
] extended attribute must not be used on an attribute declared on a namespace.
See the Attributes section for how
[LegacyLenientSetter
] is to be implemented.
The following IDL fragment defines an interface that uses the
[LegacyLenientSetter
] extended
attribute.
[Exposed =Window ]interface Example { [LegacyLenientSetter ]readonly attribute DOMString x ;readonly attribute DOMString y ; };
A JavaScript implementation that supports this interface will have a setter on the accessor property that correspond to x, which allows any assignment to be ignored in strict mode.
"use strict" ; var example= getExample(); // Get an instance of Example. // Fine; while we are in strict mode, there is a setter that is a no-op. example. x= 1 ; // Throws a TypeError, since we are in strict mode and there is no setter. example. y= 1 ;
3.4.3. [LegacyLenientThis]
If the [LegacyLenientThis
] extended attribute appears on a regular attribute,
it indicates that invocations of the attribute’s getter or setter
with a
The [LegacyLenientThis
] extended attribute
must take no arguments.
It must not be used on a static attribute.
The [LegacyLenientThis
] extended attribute must not be used on an attribute declared on a namespace.
See the Attributes section for how
[LegacyLenientThis
]
is to be implemented.
The following IDL fragment defines an interface that uses the
[LegacyLenientThis
] extended
attribute.
[Exposed =Window ]interface Example { [LegacyLenientThis ]attribute DOMString x ;attribute DOMString y ; };
A JavaScript implementation that supports this interface will
allow the getter and setter of the accessor property that corresponds
to x to be invoked with something other than an Example
object.
var example= getExample(); // Get an instance of Example. var obj= { }; // Fine. example. x; // Ignored, since the this value is not an Example object and [LegacyLenientThis] is used. Object. getOwnPropertyDescriptor( Example. prototype, "x" ). get. call( obj); // Also ignored, since Example.prototype is not an Example object and [LegacyLenientThis] is used. Example. prototype. x; // Throws a TypeError, since Example.prototype is not an Example object. Example. prototype. y;
3.4.4. [LegacyNamespace]
Instead of using this feature, interface names can be formed with a naming convention of starting with a particular prefix for a set of interfaces, as part of the identifier, without the intervening dot.
If the [LegacyNamespace
] extended attribute appears on an interface, it indicates that
the interface object for this interface will not be created as a property of the global
object, but rather as a property of the namespace identified by the argument to the extended
attribute.
The [LegacyNamespace
] extended attribute must take an identifier.
This identifier must be the identifier of a namespace definition.
The [LegacyNamespace
] and [LegacyNoInterfaceObject
]
extended attributes must not be specified on the same interface.
See § 3.13.1 Namespace object for details on how an interface is exposed on a namespace.
LegacyNamespace
] to be defined inside of it.
namespace Foo { }; [LegacyNamespace =Foo ]interface Bar {constructor (); };
In a JavaScript implementation of the above namespace and interface, the constructor Bar can be accessed as follows:
var instance= new Foo. Bar();
3.4.5. [LegacyNoInterfaceObject]
If the [LegacyNoInterfaceObject
] extended attribute appears on an interface,
it indicates that an interface object will not exist for the interface in the JavaScript binding.
The [LegacyNoInterfaceObject
] extended attribute
must take no arguments.
The [LegacyNoInterfaceObject
] extended attribute
must not be specified on an interface that has any constructors or static operations defined on it.
An interface that does not have the [LegacyNoInterfaceObject
] extended
attribute specified must not inherit
from an interface that has the [LegacyNoInterfaceObject
] extended
attribute specified.
See § 3.7 Interfaces for the specific requirements that the use of
[LegacyNoInterfaceObject
] entails.
The following IDL fragment defines two interfaces, one whose interface object is exposed on the JavaScript global object, and one whose isn’t:
[Exposed =Window ]interface Storage {undefined addEntry (unsigned long key ,any value ); }; [Exposed =Window ,LegacyNoInterfaceObject ]interface Query {any lookupEntry (unsigned long key ); };
A JavaScript implementation of the above IDL would allow
manipulation of Storage
’s
prototype, but not Query
’s.
typeof Storage; // evaluates to "object" // Add some tracing alert() call to Storage.addEntry. var fn= Storage. prototype. addEntry; Storage. prototype. addEntry= function ( key, value) { alert( 'Calling addEntry()' ); return fn. call( this , key, value); }; typeof Query; // evaluates to "undefined" var fn= Query. prototype. lookupEntry; // exception, Query isn’t defined
3.4.6. [LegacyNullToEmptyString]
If the [LegacyNullToEmptyString
] extended attribute appears on the DOMString
or USVString
type,
it creates a new IDL type such that that when a JavaScript null
", which is the default, it will be converted to the empty string.
The [LegacyNullToEmptyString
] extended attribute must not be associated with a type that is not DOMString
or USVString
.
Note: This means that even DOMString?
must not use [LegacyNullToEmptyString
], since
See § 3.2.10 DOMString for the specific requirements that the use of [LegacyNullToEmptyString
] entails.
[Exposed =Window ]interface Dog {attribute DOMString name ;attribute [LegacyNullToEmptyString ]DOMString owner ;boolean isMemberOfBreed ([LegacyNullToEmptyString ]DOMString breedName ); };
A JavaScript implementation implementing the Dog
interface would convert a owner
property or passed as the
argument to the isMemberOfBreed
function
to the empty string rather than "null
":
var d= getDog(); // Assume d is a platform object implementing the Dog // interface. d. name= null ; // This assigns the string "null" to the .name // property. d. owner= null ; // This assigns the string "" to the .owner property. d. isMemberOfBreed( null ); // This passes the string "" to the isMemberOfBreed // function.
3.4.7. [LegacyOverrideBuiltIns]
If the [LegacyOverrideBuiltIns
] extended attribute appears on an interface,
it indicates that for a legacy platform object implementing the interface,
properties corresponding to all of
the object’s supported property names will appear to be on the object,
regardless of what other properties exist on the object or its
prototype chain. This means that named properties will always shadow
any properties that would otherwise appear on the object.
This is in contrast to the usual behavior, which is for named properties
to be exposed only if there is no property with the
same name on the object itself or somewhere on its prototype chain.
The [LegacyOverrideBuiltIns
]
extended attribute must take no arguments and must not appear on an interface
that does not define a named property getter or that also is declared with the [Global
] extended attribute.
If the extended attribute is specified on
a partial interface definition, then that partial interface definition must
be the part of the interface definition that defines
the named property getter.
If the [LegacyOverrideBuiltIns
] extended attribute is specified on a partial interface definition, it is considered to appear on the interface itself.
See § 3.9 Legacy platform objects and § 3.9.3 [[DefineOwnProperty]] for the specific requirements that the use of
[LegacyOverrideBuiltIns
] entails.
The following IDL fragment defines two interfaces, one that has a named property getter and one that does not.
[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 ); };
In a JavaScript implementation of these two interfaces, getting certain properties on objects implementing the interfaces will result in different values:
// Obtain an instance of StringMap. Assume that it has "abc", "length" and // "toString" as supported property names. var map1= getStringMap(); // This invokes the named property getter. map1. abc; // This fetches the "length" property on the object that corresponds to the // length attribute. map1. length; // This fetches the "toString" property from the object’s prototype chain. map1. toString; // Obtain an instance of StringMap2. Assume that it also has "abc", "length" // and "toString" as supported property names. var map2= getStringMap2(); // This invokes the named property getter. map2. abc; // This also invokes the named property getter, despite the fact that the "length" // property on the object corresponds to the length attribute. map2. length; // This too invokes the named property getter, despite the fact that "toString" is // a property in map2’s prototype chain. map2. toString;
3.4.8. [LegacyTreatNonObjectAsNull]
If the [LegacyTreatNonObjectAsNull
] extended attribute appears on a callback function, then
it indicates that any value assigned to an attribute whose type is a nullable callback function will be converted more loosely: if the value is not an object, it will be
converted to null, and if the value is not callable, it will be converted to a callback function value that does nothing when called.
See § 3.2.20 Nullable types — T?, § 3.2.19 Callback function types and § 3.12 Invoking callback functions for the specific requirements that the use of
[LegacyTreatNonObjectAsNull
] entails.
The following IDL fragment defines an interface that has one
attribute whose type is a [LegacyTreatNonObjectAsNull
]-annotated callback function and another whose type is a callback function without the extended attribute:
callback OccurrenceHandler =undefined (DOMString details ); [LegacyTreatNonObjectAsNull ]callback ErrorHandler =undefined (DOMString details ); [Exposed =Window ]interface Manager {attribute OccurrenceHandler ?handler1 ;attribute ErrorHandler ?handler2 ; };
In a JavaScript implementation, assigning a value that is not an object (such as a Number value), or that is not callable to handler1 will have different behavior from that when assigning to handler2:
var manager= getManager(); // Get an instance of Manager. manager. handler1= function () { }; manager. handler1; // Evaluates to the function. try { manager. handler1= 123 ; // Throws a TypeError. } catch ( e) { } try { manager. handler1= {}; // Throws a TypeError. } catch ( e) { } manager. handler2= function () { }; manager. handler2; // Evaluates to the function. manager. handler2= 123 ; manager. handler2; // Evaluates to null. manager. handler2= {}; manager. handler2; // Evaluates to the object.
3.4.9. [LegacyUnenumerableNamedProperties]
If the [LegacyUnenumerableNamedProperties
] extended attribute appears on a interface that supports named properties,
it indicates that all the interface’s named properties are unenumerable.
The [LegacyUnenumerableNamedProperties
]
extended attribute must take no arguments and must not appear on an interface
that does not define a named property getter.
If the [LegacyUnenumerableNamedProperties
]
extended attribute is specified on an interface, then it applies to all its derived interfaces and
must not be specified on any of them.
See § 3.9.1 [[GetOwnProperty]] for the specific requirements that the use of
[LegacyUnenumerableNamedProperties
]
entails.
3.4.10. [LegacyUnforgeable]
If the [LegacyUnforgeable
] extended attribute appears on regular attributes or non-static operations,
it indicates that the attribute or operation
will be reflected as a JavaScript property
in a way that means its behavior cannot be modified
and that performing a property lookup on the object
will always result in the attribute’s property value being returned.
In particular, the property will be non-configurable
and will exist as an own property on the object itself
rather than on its prototype.
An attribute or operation is said to be unforgeable on a given interface A if the attribute or operation is declared on A,
and is annotated with the [LegacyUnforgeable
] extended attribute.
The [LegacyUnforgeable
] extended attribute must take no arguments.
The [LegacyUnforgeable
] extended attribute must not appear
on anything other than a regular attribute or a non-static operation.
If it does appear on an operation,
then it must appear on all operations
with the same identifier on that interface.
The [LegacyUnforgeable
] extended attribute must not be used
on an attribute declared on a namespace.
If an attribute or operation X is unforgeable on an interface A, and A is one of the inherited interfaces of another interface B, then B must not have a regular attribute or non-static operation with the same identifier as X.
For example, the following is disallowed:
[Exposed =Window ]interface A1 { [LegacyUnforgeable ]readonly attribute DOMString x ; }; [Exposed =Window ]interface B1 :A1 {undefined x (); // Invalid; would be shadowed by A1’s x. }; [Exposed =Window ]interface B2 :A1 { };B2 includes M1 ;interface mixin M1 {undefined x (); // Invalid; B2’s copy of x would be shadowed by A1’s x. };
See § 3.7.6 Attributes, § 3.7.7 Operations, § 3.8 Platform objects implementing interfaces, § 3.9 Legacy platform objects and § 3.9.3 [[DefineOwnProperty]] for the specific requirements that the use of
[LegacyUnforgeable
] entails.
The following IDL fragment defines
an interface that has two attributes,
one of which is designated as [LegacyUnforgeable
]:
[Exposed =Window ]interface System { [LegacyUnforgeable ]readonly attribute DOMString username ;readonly attribute long long loginTime ; };
In a JavaScript implementation of the interface, the username attribute will be exposed as a non-configurable property on the object itself:
var system= getSystem(); // Get an instance of System. system. hasOwnProperty( "username" ); // Evaluates to true. system. hasOwnProperty( "loginTime" ); // Evaluates to false. System. prototype. hasOwnProperty( "username" ); // Evaluates to false. System. prototype. hasOwnProperty( "loginTime" ); // Evaluates to true. try { // This call would fail, since the property is non-configurable. Object. defineProperty( system, "username" , { value: "administrator" }); } catch ( e) { } // This defineProperty call would succeed, because System.prototype.loginTime // is configurable. var forgedLoginTime= 5 ; Object. defineProperty( System. prototype, "loginTime" , { value: forgedLoginTime}); system. loginTime; // So this now evaluates to forgedLoginTime.
3.4.11. [LegacyWindowAlias]
If the [LegacyWindowAlias
] extended attribute appears on an interface,
it indicates that the Window
interface will have a property
for each identifier mentioned in the extended attribute,
whose value is the interface object for the interface.
The [LegacyWindowAlias
] extended attribute must either take an identifier or take an identifier list.
The LegacyWindowAlias
]'s identifiers.
Each of the identifiers of [LegacyWindowAlias
]
must not be the same as one used by a [LegacyWindowAlias
]
extended attribute on this interface or another interface,
must not be the same as the identifier used by a [LegacyFactoryFunction
]
extended attribute on this interface or another interface,
must not be the same as an identifier of an interface that has an interface object,
and must not be one of the reserved identifiers.
The [LegacyWindowAlias
] and [LegacyNoInterfaceObject
]
extended attributes must not be specified on the same interface.
The [LegacyWindowAlias
] and [LegacyNamespace
]
extended attributes must not be specified on the same interface.
The [LegacyWindowAlias
] extended attribute must not be specified
on an interface that does not include the Window
interface in its exposure set.
An interface must not have more than one [LegacyWindowAlias
] extended attributes specified.
See § 3.7 Interfaces for details on how legacy window aliases are to be implemented.
The following IDL defines an interface that uses the
[LegacyWindowAlias
] extended attribute.
[Exposed =Window ,LegacyWindowAlias =WebKitCSSMatrix ]interface DOMMatrix :DOMMatrixReadOnly { // ... };
A JavaScript implementation that supports this interface will
expose two properties on the Window
object with the same value
and the same characteristics;
one for exposing the interface object normally,
and one for exposing it with a legacy name.
WebKitCSSMatrix=== DOMMatrix; // Evaluates to true. var m= new WebKitCSSMatrix(); // Creates a new object that // implements DOMMatrix. m. constructor === DOMMatrix; // Evaluates to true. m. constructor === WebKitCSSMatrix; // Evaluates to true. {}. toString. call( m); // Evaluates to '[object DOMMatrix]'.
3.5. Security
Certain algorithms in the sections below are defined to perform a security check on a given object. This check is used to determine whether a given operation invocation or attribute access should be allowed. The security check takes the following three inputs:
-
the platform object on which the operation invocation or attribute access is being done,
-
the identifier of the operation or attribute, and
-
the type of the function object – "
method
" (when it corresponds to an IDL operation), or "getter
" or "setter
" (when it corresponds to the getter or setter function of an IDL attribute).
Note: The HTML Standard defines how a security check is performed. [HTML]
3.6. Overload resolution algorithm
In order to define how function invocations are resolved, the overload resolution algorithm is defined. Its input is an effective overload set, S, and a list of JavaScript values, args. Its output is a pair consisting of the operation or extended attribute of one of S’s entries and a list of IDL values or the special value “missing”. The algorithm behaves as follows:
-
Let maxarg be the length of the longest type list of the entries in S.
-
Let n be the size of args.
-
Initialize argcount to be min(maxarg, n).
-
Remove from S all entries whose type list is not of length argcount.
-
Initialize d to −1.
-
Initialize method to
undefined . -
If there is more than one entry in S, then set d to be the distinguishing argument index for the entries of S.
-
Initialize values to be an empty list, where each entry will be either an IDL value or the special value “missing”.
-
Initialize i to 0.
-
While i < d:
-
Let V be args[i].
-
Let type be the type at index i in the type list of any entry in S.
Note: All entries in S at this point have the same type and optionality value at index i.
-
Let optionality be the value at index i in the list of optionality values of any entry in S.
-
If optionality is “optional” and V is
undefined , then:-
If the argument at index i is declared with a default value, then append to values that default value.
-
Otherwise, append to values the special value “missing”.
-
-
Otherwise, append to values the result of converting V to IDL type type.
-
Set i to i + 1.
-
-
If i = d, then:
-
Let V be args[i].
Note: This is the argument that will be used to resolve which overload is selected.
-
If V is
undefined , and there is an entry in S whose list of optionality values has “optional” at index i, then remove from S all other entries. -
Otherwise: if V is
null orundefined , and there is an entry in S that has one of the following types at position i of its type list,-
an annotated type whose inner type is one of the above types
-
a union type or annotated union type that includes a nullable type or that has a dictionary type in its flattened members
then remove from S all other entries.
-
Otherwise: if V is a platform object, and there is an entry in S that has one of the following types at position i of its type list,
-
an interface type that V implements
-
a nullable version of any of the above types
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
-
Otherwise: if V is an Object, V has an [[ArrayBufferData]] internal slot, and there is an entry in S that has one of the following types at position i of its type list,
-
a nullable version of either of the above types
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if V is an Object, V has a [[DataView]] internal slot, and there is an entry in S that has one of the following types at position i of its type list,
-
a nullable version of either of the above types
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if V is an Object, V has a [[TypedArrayName]] internal slot, and there is an entry in S that has one of the following types at position i of its type list,
-
a typed array type whose name is equal to the value of V’s [[TypedArrayName]] internal slot
-
a nullable version of either of the above types
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
-
Otherwise: if IsCallable(V) is true, and there is an entry in S that has one of the following types at position i of its type list,
-
a callback function type
-
a nullable version of any of the above types
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
-
Otherwise: if V is an Object and there is an entry in S that has one of the following types at position i of its type list,
-
an annotated type whose inner type is a sequence type
-
a union type, nullable union type, or annotated union type that has a sequence type in its flattened member types
and after performing the following steps,
-
Let method be ? GetMethod(V,
%Symbol.iterator%
).
method is not
undefined , then remove from S all other entries. -
Otherwise: if V is an Object and there is an entry in S that has one of the following types at position i of its type list,
-
a nullable version of any of the above types
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if V is a Boolean and there is an entry in S that has one of the following types at position i of its type list,
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if V is a Number and there is an entry in S that has one of the following types at position i of its type list,
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if V is a BigInt and there is an entry in S that has one of the following types at position i of its type list,
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if there is an entry in S that has one of the following types at position i of its type list,
-
a nullable version of any of the above types
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if there is an entry in S that has one of the following types at position i of its type list,
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if there is an entry in S that has one of the following types at position i of its type list,
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
then remove from S all other entries.
-
Otherwise: if there is an entry in S that has one of the following types at position i of its type list,
-
an annotated type whose inner type is one of the above types
-
a union type, nullable union type, or annotated union type that has one of the above types in its
-