Web IDL

Living Standard — Last Updated

Participate:
GitHub whatwg/webidl (new issue, open issues)
Chat on Matrix
Commits:
GitHub whatwg/webidl/commits
Snapshot as of this commit
@webidl
Tests:
web-platform-tests webidl/ (ongoing work)
Translations (non-normative):
日本語

Abstract

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.

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 Definitions grammar symbol. The set of IDL fragments that an implementation supports is not ordered. See IDL grammar for the complete grammar and an explanation of the notation used.

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 Definition) can be preceded by a list of extended attributes (matching ExtendedAttributeList), which can control how the definition will be handled in language bindings. The extended attributes defined by this specification that are language binding agnostic are discussed in § 2.14 Extended attributes, while those specific to the JavaScript language binding are discussed in § 3.3 Extended attributes.

[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 identifier token somewhere in the declaration:

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 identifier token with any leading U+005F (_) removed.

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 identifier token or by one of the keywords that match the ArgumentNameKeyword symbol. If one of these keywords is used, it need not be escaped with a leading underscore.

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 identifier token is used, then the identifier of the operation argument is the value of that token with any leading U+005F (_) removed. If instead one of the ArgumentNameKeyword keyword token is used, then the identifier of the operation argument is simply that token.

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 interface InterfaceRest) that declares some state and behavior that an object implementing that interface will expose.

[extended_attributes]
interface identifier {
  /* interface_members... */
};

An interface is a specification of a set of interface members (matching InterfaceMembers). These are the members that appear between the braces in the interface declaration.

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.

The list of inclusive inherited interfaces of an interface I is defined as follows:
  1. Let result be « ».

  2. Let interface be I.

  3. While interface is not null:

    1. Append interface to result.

    2. Set interface to the interface that I inherits from, if any, and null otherwise.

  4. Return result.

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 ExtendedAttributeList), which can control how the interface member will be handled in language bindings.

[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 partial interface PartialInterfaceRest). The identifier of a partial interface definition must be the same as the identifier of an interface definition. All of the members that appear on each of the partial interfaces are considered to be members of the interface itself.

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:

  1. Let identifier be the identifier of interface.

  2. If interface has a [LegacyNamespace] extended attribute, then:

    1. Let namespace be the identifier argument of the [LegacyNamespace] extended attribute.

    2. Return the concatenation of « namespace, identifier » with separator U+002E (.).

  3. 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 MixinRest) that declares state and behavior that can be included by one or more interfaces, and that are exposed by objects that implement an interface that includes the interface mixin.

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 MixinMembers), which are the constants, regular operations, regular attributes, and stringifiers that appear between the braces in the interface mixin declaration.

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 partial interface MixinRest). The identifier of a partial interface mixin definition must be the same as the identifier of an interface mixin definition. All of the members that appear on each of the partial interface mixin definitions are considered to be members of the interface mixin itself, and—by extension—of the interfaces that include the interface mixin.

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 IncludesStatement) used to declare that all objects implementing an interface I (identified by the first identifier) must additionally include the members of interface mixin M (identified by the second identifier). Interface I is said to include interface mixin M.

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
InterfaceOrMixin ::
    InterfaceRest
    MixinRest
Partial ::
    partial PartialDefinition
PartialDefinition ::
    interface PartialInterfaceOrPartialMixin
    PartialDictionary
    Namespace
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 callback interface identifier { CallbackInterfaceMembers } ;. It can be implemented by any object, as described in § 2.12 Objects implementing interfaces.

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 CallbackInterfaceMembers). These are the members that appear between the braces in the interface declaration.

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 InterfaceMembers, MixinMembers, and NamespaceMembers), which are the constants, attributes, operations, and other declarations that appear between the braces of their declarations. Attributes describe the state that an object implementing the interface, interface mixin, or namespace will expose, and operations describe the behaviors that can be invoked on the object. Constants declare named constant values that are exposed as a convenience to users of objects in the system.

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:

Interfaces Callback interfaces Interface mixins Namespaces
Constants
Regular attributes Only read only attributes
Static attributes
Regular Operations
Stringifiers
Special Operations
Static Operations
Iterable declarations
Asynchronously iterable declarations
Maplike declarations
Setlike declarations

2.5.1. Constants

A constant is a declaration (matching Const) used to bind a constant value to a name. Constants can appear on interfaces and callback interfaces.

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 ConstType) must not be any type other than a primitive type. If an identifier is used, it must reference a typedef whose type is a primitive type.

The ConstValue part of a constant declaration gives the value of the constant, which can be one of the two boolean literal tokens (true and false), an integer token, a decimal token, or one of the three special floating point constant values (-Infinity, Infinity and NaN).

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 [], and the default dictionary {} cannot be used as the value of a constant.

The value of the boolean literal tokens true and false are the IDL boolean values true and false.

The value of an integer token is an integer whose value is determined as follows:

  1. Let S be the sequence of scalar values matched by the integer token.

  2. Let sign be −1 if S begins with U+002D (-), and 1 otherwise.

  3. 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.

  4. 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.

  5. Return sign × number.

The type of an integer token is the same as the type of the constant, dictionary member or optional argument it is being used as the value of. The value of the integer token must not lie outside the valid range of values for its type, as given in § 2.13 Types.

The value of a decimal token is either an IEEE 754 single-precision floating point number or an IEEE 754 double-precision floating point number, depending on the type of the constant, dictionary member or optional argument it is being used as the value for, determined as follows:
  1. Let S be the sequence of scalar values matched by the decimal token.

  2. Let result be the Mathematical Value that would be obtained if S were parsed as a JavaScript NumericLiteral.

  3. If the decimal token is being used as the value for a float or unrestricted float, then the value of the decimal token is the IEEE 754 single-precision floating point number closest to result.

  4. Otherwise, the decimal token is being used as the value for a double or unrestricted double, and the value of the decimal token is the IEEE 754 double-precision floating point number closest to result. [IEEE-754]

The value of a constant value specified as Infinity, -Infinity, or NaN is either an IEEE 754 single-precision floating point number or an IEEE 754 double-precision floating point number, depending on the type of the constant, dictionary member, or optional argument it is being used as the value for:

Type unrestricted float, constant value Infinity

The value is the IEEE 754 single-precision positive infinity value.

Type unrestricted double, constant value Infinity

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 value NaN

The value is the IEEE 754 single-precision NaN value with the bit pattern 0x7fc00000.

Type unrestricted double, constant value NaN

The value is the IEEE 754 double-precision NaN value with the bit pattern 0x7ff8000000000000.

The type of a decimal token is the same as the type of the constant, dictionary member or optional argument it is being used as the value of. The value of the decimal token must not lie outside the valid range of values for its type, as given in § 2.13 Types. Also, Infinity, -Infinity and NaN must not be used as the value of a float or double.

The value of the null token is the special null value that is a member of the nullable types. The type of the null token is the same as the type of the constant, dictionary member or optional argument it is being used as the value of.

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 inherit AttributeRest, static OptionalReadOnly AttributeRest, stringifier OptionalReadOnly AttributeRest, OptionalReadOnly AttributeRest, or AttributeRest) that is used to declare data fields with a given type and identifier whose value can be retrieved and (in some cases) changed. There are two kinds of attributes:

  1. 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;
    };
    
  2. 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 static keyword, then it declares a regular attribute. Otherwise, it declares a static attribute. Note that in addition to being interface members, read only regular attributes can be namespace members as well.

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 Type) that appears after the attribute keyword. If the Type is an identifier or an identifier followed by ?, then the identifier must identify an interface, enumeration, callback function, callback interface or typedef.

The type of the attribute, after resolving typedefs, must not be a nullable or non-nullable version of any of the following types:

The attribute is read only if the readonly keyword is used before the attribute keyword. An object that implements the interface on which a read only attribute is defined will not allow assignment to that attribute. It is language binding specific whether assignment is simply disallowed by the language, ignored or an exception is thrown.

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 inherit in the declaration. The read only attribute from which the attribute inherits its getter is the attribute with the same identifier on the closest ancestor interface of the one on which the inheriting attribute is defined. The attribute whose getter is being inherited must be of the same type as the inheriting attribute.

Note: The grammar ensures that inherit does not appear on a read only attribute or a static attribute.

[Exposed=Window]
interface Ancestor {
  readonly attribute TheType theIdentifier;
};

[Exposed=Window]
interface Derived : Ancestor {
  inherit attribute TheType theIdentifier;
};

When the stringifier keyword is used in a regular attribute declaration, it indicates that objects implementing the interface will be stringified to the value of the attribute. See § 2.5.5 Stringifiers for details.

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 static RegularOperation, stringifier, RegularOperation or SpecialOperation) that defines a behavior that can be invoked on objects implementing the interface. There are three kinds of operation:

  1. 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... */);
    };
    
  2. 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... */);
    };
    
  3. 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 static keyword, then it declares a regular operation. If the operation has a special keyword used in its declaration (that is, any keyword matching Special, or the stringifier keyword), then it declares a special operation. A single operation can declare both a regular operation and a special operation; see § 2.5.6 Special operations for details on special operations. Note that in addition to being interface members, regular operations can also be callback interface members and namespace members.

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 Type) that appears before the operation’s optional identifier. If the return type is an identifier followed by ?, then the identifier must identify an interface, dictionary, enumeration, callback function, callback interface or typedef.

An operation’s arguments (matching ArgumentList) are given between the parentheses in the declaration. Each individual argument is specified as a type (matching Type) followed by an identifier (matching ArgumentName).

Note: For expressiveness, the identifier of an operation argument can also be specified as one of the keywords matching the ArgumentNameKeyword symbol without needing to escape it.

If the Type of an operation argument is an identifier followed by ?, then the identifier must identify an interface, enumeration, callback function, callback interface, or typedef. If the operation argument type is an identifier not followed by ?, then the identifier must identify any one of those definitions or a dictionary.

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 ExtendedAttributeList), which can control how a value passed as the argument will be handled in language bindings.

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 ... token just after the argument type. Declaring an operation to be variadic indicates that the operation can be invoked with any number of arguments after that final argument. Those extra implied formal arguments are of the same type as the final explicit argument in the operation declaration. The final argument can also be omitted when invoking the operation. An argument must not be declared with the ... token unless it is the final argument in the operation’s argument list.

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 ... token is used in their argument lists.

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 optional keyword. The final argument of a variadic operation is also considered to be an optional argument. Declaring an argument to be optional indicates that the argument value can be omitted when the operation is invoked. The final argument in an operation must not explicitly be declared to be optional if the operation is variadic.

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 DefaultValue), then that gives the optional argument its default value. The implicitly optional final argument of a variadic operation must not have a default value specified. The default value is the value to be assumed when the operation is called with the corresponding argument omitted.

interface interface_identifier {
  return_type identifier(type identifier, optional type identifier = "value");
};

It is strongly suggested not to use a default value of true for boolean-typed arguments, as this can be confusing for authors who might otherwise expect the default conversion of undefined to be used (i.e., false). [API-DESIGN-PRINCIPLES]

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 {}, but in the case of a union type that has a dictionary type as one of its flattened member types a default value could be provided that initializes some other member of the union.

When a boolean literal token (true or false), the null token, an integer token, a decimal token or one of the three special floating point literal values (Infinity, -Infinity or NaN) is used as the default value, it is interpreted in the same way as for a constant.

When the undefined token is used as the default value, the value is the IDL undefined value.

Optional argument default values can also be specified using a string token, whose value is a string type determined as follows:
  1. Let S be the sequence of scalar values matched by the string token with its leading and trailing U+0022 (") scalar values removed.

  2. 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 [], which represents an empty sequence value. The type of this value is the same as the type of the optional argument it is being used as the default value of. That type must be a sequence type, a nullable type whose inner type is a sequence type or a union type or nullable union type that has a sequence type in its flattened member types.

Optional argument default values can also be specified using the two token value {}, which represents a default-initialized (as if from ES null or an object with no properties) dictionary value. The type of this value is the same as the type of the optional argument it is being used as the default value of. That type must be a dictionary type, or a union type that has a dictionary type in its flattened member types.

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 false.

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:

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:

  1. Let json be a new map.

  2. For each attribute identifier attr in « "from", "to", "amount", "description" »:

    1. Let value be the result of running the getter steps of attr on this.

    2. Set json[attr] to value.

  3. 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 Constructor), it indicates that it is possible to create objects that implement the interface using a constructor.

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 ) ;
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.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 stringifier keyword, which creates a stringifier operation when used alone.

interface interface_identifier {
  stringifier;
};

Prose accompanying the interface must define the stringification behavior of the interface.

The stringifier keyword can also be placed on an attribute. In this case, the string to convert the object to is the value of the attribute. The stringifier keyword must not be placed on an attribute unless it is declared to be of type 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:

  1. If this's family name is null, then return this's given name.

  2. Return the concatenation of this's given name, followed by U+0020 SPACE, followed by this's family name.

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 getter Defines behavior for when an object is indexed for property retrieval.
Setters setter Defines behavior for when an object is indexed for property assignment or creation.
Deleters deleter 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:

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 null if an attempt is made to look up a non-existing entry in the 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:

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 static keyword in their declarations.

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:

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
For constructors
For legacy factory functions

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:

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 algorithm below describes how to compute the effective overload set. The following input variables are used, if they are required:

Whenever an argument of an extended attribute is mentioned, it is referring to an argument of the extended attribute’s named argument list.

  1. Let S be an ordered set.

  2. 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.

  3. 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.

  4. Let max be max(maxarg, N).

  5. For each operation or extended attribute X in F:

    1. Let arguments be the list of arguments X is declared to take.

    2. Let n be the size of arguments.

    3. Let types be a type list.

    4. Let optionalityValues be an optionality list.

    5. For each argument in arguments:

      1. Append the type of argument to types.

      2. Append "variadic" to optionalityValues if argument is a final, variadic argument, "optional" if argument is optional, and "required" otherwise.

    6. Append the tuple (X, types, optionalityValues) to S.

    7. If X is declared to be variadic, then:

      1. For each i in the range n to max − 1, inclusive:

        1. Let t be a type list.

        2. Let o be an optionality list.

        3. For each j in the range 0 to n − 1, inclusive:

          1. Append types[j] to t.

          2. Append optionalityValues[j] to o.

        4. For each j in the range n to i, inclusive:

          1. Append types[n − 1] to t.

          2. Append "variadic" to o.

        5. Append the tuple (X, t, o) to S.

    8. Let i be n − 1.

    9. While i ≥ 0:

      1. If arguments[i] is not optional (i.e., it is not marked as "optional" and is not a final, variadic argument), then break.

      2. Let t be a type list.

      3. Let o be an optionality list.

      4. For each j in the range 0 to i − 1, inclusive:

        1. Append types[j] to t.

        2. Append optionalityValues[j] to o.

      5. 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).

      6. Set i to i − 1.

  6. 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.

  1. 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.

    None of the following pairs are distinguishable:
  2. 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.

  3. 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.

  4. 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
    undefined
    boolean
    numeric types
    bigint
    string types
    object
    symbol
    interface-like
    callback function
    dictionary-like
    sequence-like
    undefined
    boolean
    numeric types (b)
    bigint
    string types
    object
    symbol
    interface-like (a)
    callback function (c)
    dictionary-like
    sequence-like
    1. The two identified interface-like types are not the same, and no single platform object implements both interface-like types.

    2. 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.

    3. 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 and DOMString are distinguishable because there is a ● at the intersection of numeric types with string types.
    double and long 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 from Iface because there’s a ● at the intersection of dictionary-like and interface-like, but it is not distinguishable from Dict 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);
};

since DOMString and USVString are not distinguishable.

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 undefined cannot be converted to a 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:

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 Iterable) in the body of the interface.

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:

  1. 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;

  2. 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 the SessionManager 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 username of 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 AsyncIterable) in the body of the interface.

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 ArgumentList) must all be optional arguments.

In the JavaScript language binding, an interface that is asynchronously iterable will have %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:

  1. Set iterator’s current state to "not yet started".

To get the next iteration result for a SessionManager manager and its async iterator iterator:

  1. Let promise be a new promise.

  2. 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.

  3. If key is null, then:

    1. Resolve promise with end of iteration.

  4. Otherwise:

    1. Let session be the Session object corresponding to key.

    2. Resolve promise with (username, session).

    3. Set iterator’s current state to username.

  5. 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 username of 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 ReadWriteMaplike or readonly MaplikeRest) in the body of the interface.

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 readonly keyword is not used, then it also supports an API for modifying the map entries.

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 readonly keyword is used, this includes 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
ReadOnlyMemberRest ::
    AttributeRest
    MaplikeRest
    SetlikeRest
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 ReadWriteSetlike or readonly SetlikeRest) in the body of the interface.

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 readonly keyword is not used, then it also supports an API for modifying the set entries.

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 readonly keyword is used, this includes 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
ReadOnlyMemberRest ::
    AttributeRest
    MaplikeRest
    SetlikeRest
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) that declares a global singleton with associated behaviors.

namespace identifier {
  /* namespace_members... */
};

A namespace is a specification of a set of namespace members (matching NamespaceMembers), which are the regular operations, read only regular attributes, and constants that appear between the braces in the namespace declaration. These operations and attributes describe the behaviors packaged into the namespace.

As with interfaces, the IDL for namespaces can be split into multiple parts by using partial namespace definitions (matching partial Namespace). The identifier of a partial namespace definition must be the same as the identifier of a namespace definition. All of the members that appear on each of the partial namespace definitions are considered to be members of the namespace itself.

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
PartialDefinition ::
    interface PartialInterfaceOrPartialMixin
    PartialDictionary
    Namespace
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) used to define an ordered map data type with a fixed, ordered set of entries, termed dictionary members, where keys are strings and values are of a particular type specified in the definition.

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 undefined for the property corresponding to a dictionary member is treated the same as omitting that property. Thus, it will cause an error if the member is required, or will trigger the default value if one is present, or will result in no entry existing in the dictionary value otherwise.

As with operation argument default values, it is strongly encouraged not to use true as the default value for boolean-typed dictionary members, as this can be confusing for authors who might otherwise expect the default conversion of undefined to be used (i.e., false). [API-DESIGN-PRINCIPLES]

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:

  1. Let identifiers be « 1, 3, 7 ».

  2. Return «[ "name" → "test", "serviceIdentifiers" → identifiers ]».

Each dictionary member (matching DictionaryMember) is specified as a type (matching Type) followed by an identifier (given by an identifier token following the type). The identifier is the key name of the key–value pair. If the Type is an identifier followed by ?, then the identifier must identify an interface, enumeration, callback function, callback interface or typedef. If the dictionary member type is an identifier not followed by ?, then the identifier must identify any one of those definitions or a dictionary.

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 DefaultValue), then that gives the dictionary member its default value, which is the value used by default when author code or specification text does not provide a value for that member.

dictionary identifier {
  type identifier = "value";
};

When a boolean literal token (true or false), the null token, an integer token, a decimal token, one of the three special floating point literal values (Infinity, -Infinity or NaN), a string token, the two token sequence [], or the two token sequence {} is used as the default value, it is interpreted in the same way as for an operation's optional argument default value.

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 required keyword, the member is considered a required dictionary member.

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:

As with interfaces, the IDL for dictionaries can be split into multiple parts by using partial dictionary definitions (matching partial Dictionary). The identifier of a partial dictionary definition must be the same as the identifier of a dictionary definition. All of the members that appear on each of the partial dictionary definitions are considered to be members of the dictionary itself.

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
PartialDefinition ::
    interface PartialInterfaceOrPartialMixin
    PartialDictionary
    Namespace
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:

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:

Throw a TypeError.

To throw a new DOMException with name "NotAllowedError":

Throw a "NotAllowedError" DOMException.

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:

These requirements mean that the inherited code property of these interfaces will always return 0.

The definition for a 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.

The new ProtocolXError(message, options) constructor steps are:
  1. Set this's name to "ProtocolXError".

  2. Set this's message to message.

  3. Set this's error code to options["errorCode"].

The errorCode getter steps are to return this's error code.

ProtocolXError objects are serializable objects.

Their serialization steps, given value and serialized, are:
  1. Run the DOMException serialization steps given value and serialized.

  2. Set serialized.[[ErrorCode]] to value’s error code.

Their deserialization steps, given serialized and value, are:
  1. Run the DOMException deserialization steps given serialized and value.

  2. 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 Enum) used to declare a type whose valid values are a set of predefined strings. Enumerations can be used to restrict the possible 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 string literals. The list of enumeration values must not include duplicates.

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 grams

  undefined 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 CallbackRest) used to declare a function type.

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 Type and ArgumentList) on the right side of the equals sign gives the signature of the callback function type.

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) used to declare a new name for a type. This new name is not exposed by language bindings; it is purely used as a shorthand for referencing the type in the IDL.

typedef type identifier;

The type being given a new name is specified after the typedef keyword (matching TypeWithExtendedAttributes), and the identifier token following the type gives the name.

The Type must not be the identifier of the same or another typedef.

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
ConstType ::
    PrimitiveType
    identifier
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 token.

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 corresponds to booleans.

boolean constant values in IDL are represented with the true and false tokens.

2.13.4. byte

The byte type corresponds to 8-bit signed integers.

byte constant values in IDL are represented with integer tokens.

2.13.5. octet

The octet type corresponds to 8-bit unsigned integers.

octet constant values in IDL are represented with integer tokens.

2.13.6. short

The short type corresponds to 16-bit signed integers.

short constant values in IDL are represented with integer tokens.

2.13.7. unsigned short

The unsigned short type corresponds to 16-bit unsigned integers.

unsigned short constant values in IDL are represented with integer tokens.

2.13.8. long

The long type corresponds to 32-bit signed integers.

long constant values in IDL are represented with integer tokens.

2.13.9. unsigned long

The unsigned long type corresponds to 32-bit unsigned integers.

unsigned long constant values in IDL are represented with integer tokens.

2.13.10. long long

The long long type corresponds to 64-bit signed integers.

long long constant values in IDL are represented with integer tokens.

2.13.11. unsigned long long

The unsigned long long type corresponds to 64-bit unsigned integers.

unsigned long long constant values in IDL are represented with integer tokens.

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 decimal tokens.

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 decimal tokens.

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 decimal tokens.

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 decimal tokens.

2.13.16. bigint

The bigint type is an arbitrary integer type, unrestricted in range.

bigint constant values in IDL are represented with integer tokens.

2.13.17. DOMString

The DOMString type corresponds to strings.

Note: null is not a value of type DOMString. To allow null, a nullable 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 string literal.

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 string literal.

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 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 string literal.

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 null value, use the nullable type 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 null value, use a nullable type.

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 null value, use a nullable type.

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 string literal.

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 null to be a member of its set of values. Nullable types are represented in IDL by placing a U+003F (?) character after an existing type. The inner type must not be:

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 null token.

For example, a type that allows the values true, false and null is written as 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 null value, and another whose value can be a reference to a Node object or the null value:

[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 UnionType) are written as a series of types separated by the or keyword with a set of surrounding parentheses. The types which comprise the union type are known as the union’s member types.

For example, you might write (Node or DOMString) or (double or sequence<double>). When applying a ? suffix to a union type as a whole, it is placed after the closing parenthesis, as in (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:

  1. Let T be the union type.

  2. Initialize S to ∅.

  3. For each member type U of T:

    1. If U is an annotated type, then set U to be the inner type of U.

    2. If U is a nullable type, then set U to be the inner type of U.

    3. If U is a union type, then add to S the flattened member types of U.

    4. Otherwise, U is not a union type. Add U to S.

  4. 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:

  1. Let T be the union type.

  2. Initialize n to 0.

  3. For each member type U of T:

    1. If U is a nullable type, then:

      1. Set n to n + 1.

      2. Set U to be the inner type of U.

    2. If U is a union type, then:

      1. Let m be the number of nullable member types of U.

      2. Set n to n + m.

  4. 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:

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:

Union type constant values in IDL are represented in the same way that constant values of their member types would be represented.

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

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].

The extended attributes associated with an IDL type type are determined as follows:
  1. Let extended attributes be a new empty set.

  2. If type appears as part of a TypeWithExtendedAttributes production, append each of the extended attributes present in the production’s ExtendedAttributeList to extended attributes.

    [Exposed=Window]
    interface I {
        attribute [XAttr] long attrib;
        undefined f1(sequence<[XAttr] long> arg);
        undefined f2(optional [XAttr] long arg);
    
        maplike<[XAttr2] DOMString, [XAttr3] long>;
    };
    
    dictionary D {
        required [XAttr] long member;
    };
    
  3. If type is a member type of a union type U, append each of the extended attributes associated with U to extended attributes.

    [Exposed=Window]
    interface I {
        attribute [XAttr] (long or Node) attrib;
    };
    
  4. If type appears as part of a Type production directly within an Argument production, append to extended attributes all of the extended attributes present in the production’s ExtendedAttributeList 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.

  5. If type appears as part of a Type production directly within a DictionaryMember production, append to extended attributes all of the extended attributes present in the production’s ExtendedAttributeList 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.

  6. If type is a typedef, append the extended attributes associated with the type being given a new name to extended attributes.

    typedef [XAttr] long xlong;
    
  7. 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 8-bit unsigned 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.

The following IDL fragment defines an interface with two frozen array attributes, one read only and one not.
[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:

Each PersonalPreferences has associated favorite colors, a FrozenArray<DOMString>, initially equal to the result of creating a frozen array from « "purple", "aquamarine" ».

Each PersonalPreferences has an associated favorite foods, a FrozenArray<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:

  1. Let newFavoriteColors be a list of two strings representing colors, chosen randomly.

  2. 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:

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.

The following IDL fragment defines an interface with an observable array attribute:
[Exposed=Window]
interface Building {
  attribute ObservableArray<Employee> employees;
};

The behavior of the attribute could be defined like so:

The set an indexed value algorithm for Building’s employees attribute, given employee and index, is:
  1. If employee is not allowed to enter the building today, then throw a "NotAllowedError" DOMException.

  2. If index is greater than 200, then throw a "QuotaExceededError" DOMException.

  3. Put employee to work!

The delete an indexed value algorithm for Building’s employees attribute, given employee and index, is:

  1. 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.employees instanceof 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 ExtendedAttributeList, which is a square bracket enclosed, comma separated list of ExtendedAttributes.

The ExtendedAttribute grammar symbol matches nearly any sequence of tokens, however the extended attributes defined in this document only accept a more restricted syntax. Any extended attribute encountered in an IDL fragment is matched against the following five grammar symbols to determine which form (or forms) it is in:

Grammar symbol Form Example
ExtendedAttributeNoArgs takes no arguments [Replaceable]
ExtendedAttributeArgList takes an argument list Not currently used; previously used by [Constructor(double x, double y)]
ExtendedAttributeNamedArgList takes a named argument list [LegacyFactoryFunction=Image(DOMString src)]
ExtendedAttributeIdent takes an identifier [PutForwards=name]
ExtendedAttributeIdentList takes an identifier list [Exposed=(Window,Worker)]
ExtendedAttributeWildcard 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 true.

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]]: false, [[Enumerable]]: false, [[Configurable]]: true, [[Value]]: classString}.

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:

  1. Let x be the JavaScript value passed in to this algorithm.

  2. Let y be the result of calling ? ToString(x).

  3. Return y.

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
iframe instanceof w.Node;                  // Evaluates to false
iframe instanceof w.Object;                // Evaluates to false
iframe.appendChild instanceof Function;    // Evaluates to true
iframe.appendChild instanceof 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:

  1. If V is undefined, then return the unique undefined IDL value.

  2. If V is null, then return the null object? reference.

  3. If V is a Boolean, then return the boolean value that represents the same truth value.

  4. If V is a Number, then return the result of converting V to an unrestricted double.

  5. If V is a BigInt, then return the result of converting V to a bigint.

  6. If V is a String, then return the result of converting V to a DOMString.

  7. If V is a Symbol, then return the result of converting V to a symbol.

  8. 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 undefined value.

3.2.3. boolean

A JavaScript value V is converted to an IDL boolean value by running the following algorithm:

  1. Let x be the result of computing ToBoolean(V).

  2. Return the IDL boolean value that is the one that represents the same truth value as the JavaScript Boolean value x.

The IDL boolean value true is converted to the JavaScript true value and the IDL boolean value false is converted to the JavaScript false value.

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:

  1. Let x be ? ConvertToInt(V, 8, "signed").

  2. 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:

  1. Let x be ? ConvertToInt(V, 8, "unsigned").

  2. 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:

  1. Let x be ? ConvertToInt(V, 16, "signed").

  2. 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:

  1. Let x be ? ConvertToInt(V, 16, "unsigned").

  2. 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:

  1. Let x be ? ConvertToInt(V, 32, "signed").

  2. 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:

  1. Let x be ? ConvertToInt(V, 32, "unsigned").

  2. 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:

  1. Let x be ? ConvertToInt(V, 64, "signed").

  2. 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:

  1. Let x be ? ConvertToInt(V, 64, "unsigned").

  2. 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

IntegerPart(n):

  1. Let r be floor(abs(n)).

  2. If n < 0, then return -1 × r.

  3. Otherwise, return r.

ConvertToInt(V, bitLength, signedness):

  1. If bitLength is 64, then:

    1. Let upperBound be 253 − 1.

    2. If signedness is "unsigned", then let lowerBound be 0.

    3. 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.

  2. Otherwise, if signedness is "unsigned", then:

    1. Let lowerBound be 0.

    2. Let upperBound be 2bitLength − 1.

  3. Otherwise:

    1. Let lowerBound be -2bitLength − 1.

    2. Let upperBound be 2bitLength − 1 − 1.

  4. Let x be ? ToNumber(V).

  5. If x is −0, then set x to +0.

  6. If the conversion is to an IDL type associated with the [EnforceRange] extended attribute, then:

    1. If x is NaN, +∞, or −∞, then throw a TypeError.

    2. Set x to IntegerPart(x).

    3. If x < lowerBound or x > upperBound, then throw a TypeError.

    4. Return x.

  7. If x is not NaN and the conversion is to an IDL type associated with the [Clamp] extended attribute, then:

    1. Set x to min(max(x, lowerBound), upperBound).

    2. Round x to the nearest integer, choosing the even integer if it lies halfway between two, and choosing +0 rather than −0.

    3. Return x.

  8. If x is NaN, +0, +∞, or −∞, then return +0.

  9. Set x to IntegerPart(x).

  10. Set x to x modulo 2bitLength.

  11. If signedness is "signed" and x ≥ 2bitLength − 1, then return x − 2bitLength.

  12. Otherwise, return x.

3.2.5. float

A JavaScript value V is converted to an IDL float value by running the following algorithm:

  1. Let x be ? ToNumber(V).

  2. If x is NaN, +∞, or −∞, then throw a TypeError.

  3. 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.

  4. 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.)

  5. If y is 2128 or −2128, then throw a TypeError.

  6. If y is +0 and x is negative, return −0.

  7. 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:

  1. Let x be ? ToNumber(V).

  2. If x is NaN, then return the IDL unrestricted float value that represents the IEEE 754 NaN value with the bit pattern 0x7fc00000 [IEEE-754].

  3. 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.

  4. 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.)

  5. If y is 2128, return +∞.

  6. If y is −2128, return −∞.

  7. If y is +0 and x is negative, return −0.

  8. Return y.

Note: Since there is only a single JavaScript NaN value, it must be canonicalized to a particular single precision IEEE 754 NaN value. The NaN value mentioned above is chosen simply because it is the quiet NaN with the lowest value when its bit pattern is interpreted as an 32-bit unsigned integer.

The result of converting an IDL unrestricted float value to a JavaScript value is a Number:

  1. If the IDL unrestricted float value is a NaN, then the Number value is NaN.

  2. Otherwise, the Number value is the one that represents the same numeric value as the IDL unrestricted float value.

3.2.7. double

A JavaScript value V is converted to an IDL double value by running the following algorithm:

  1. Let x be ? ToNumber(V).

  2. If x is NaN, +∞, or −∞, then throw a TypeError.

  3. Return the IDL double value that represents the same numeric value as x.

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:

  1. Let x be ? ToNumber(V).

  2. If x is NaN, then return the IDL unrestricted double value that represents the IEEE 754 NaN value with the bit pattern 0x7ff8000000000000 [IEEE-754].

  3. Return the IDL unrestricted double value that represents the same numeric value as x.

Note: Since there is only a single JavaScript NaN value, it must be canonicalized to a particular double precision IEEE 754 NaN value. The NaN value mentioned above is chosen simply because it is the quiet NaN with the lowest value when its bit pattern is interpreted as an 64-bit unsigned integer.

The result of converting an IDL unrestricted double value to a JavaScript value is a Number:

  1. If the IDL unrestricted double value is a NaN, then the Number value is NaN.

  2. Otherwise, the Number value is the one that represents the same numeric value as the IDL unrestricted double value.

3.2.9. bigint

A JavaScript value V is converted to an IDL bigint value by running the following algorithm:

  1. Let x be ? ToBigInt(V).

  2. Return the IDL bigint value that represents the same numeric value as x.

The result of converting an IDL bigint value to a JavaScript value is a BigInt:

  1. Return the BigInt value that represents the same numeric value as the IDL bigint value.

A JavaScript value V is converted to an IDL numeric type T or bigint value by running the following algorithm:

  1. Let x be ? ToNumeric(V).

  2. If x is a BigInt, then

    1. Return the IDL bigint value that represents the same numeric value as x.

  3. Assert: x is a Number.

  4. 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:

  1. If V is null and the conversion is to an IDL type associated with the [LegacyNullToEmptyString] extended attribute, then return the DOMString value that represents the empty string.

  2. Let x be ? ToString(V).

  3. 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:

  1. Let x be ? ToString(V).

  2. If the value of any element of x is greater than 255, then throw a TypeError.

  3. Return an IDL ByteString value whose length is the length of x, and where the value of each element is the value of the corresponding element of x.

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:

  1. Let string be the result of converting V to a DOMString.

  2. 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:

  1. If V is not an Object, then throw a TypeError.

  2. 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.

A JavaScript value V is converted to an IDL symbol value by running the following algorithm:
  1. If V is not a Symbol, then throw a TypeError.

  2. 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):

  1. If V implements I, then return the IDL interface type value that represents a reference to that platform object.

  2. Throw a TypeError.

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:

  1. If V is not an Object, then throw a TypeError.

  2. 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):

  1. If jsDict is not an Object and jsDict is neither undefined nor null, then throw a TypeError.

  2. Let idlDict be an empty ordered map, representing a dictionary of type D.

  3. Let dictionaries be a list consisting of D and all of D’s inherited dictionaries, in order from least to most derived.

  4. For each dictionary dictionary in dictionaries, in order:

    1. For each dictionary member member declared on dictionary, in lexicographical order:

      1. Let key be the identifier of member.

      2. If jsDict is either undefined or null, then:

        1. Let jsMemberValue be undefined.

      3. Otherwise,

        1. Let jsMemberValue be ? Get(jsDict, key).

      4. If jsMemberValue is not undefined, then:

        1. Let idlMemberValue be the result of converting jsMemberValue to an IDL value whose type is the type member is declared to be of.

        2. Set idlDict[key] to idlMemberValue.

      5. Otherwise, if jsMemberValue is undefined but member has a default value, then:

        1. Let idlMemberValue be member’s default value.

        2. Set idlDict[key] to idlMemberValue.

      6. Otherwise, if jsMemberValue is undefined and member is required, then throw a TypeError.

  5. 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):

  1. Let O be OrdinaryObjectCreate(%Object.prototype%).

  2. Let dictionaries be a list consisting of D and all of D’s inherited dictionaries, in order from least to most derived.

  3. For each dictionary dictionary in dictionaries, in order:

    1. For each dictionary member member declared on dictionary, in lexicographical order:

      1. Let key be the identifier of member.

      2. If V[key] exists, then:

        1. Let idlValue be V[key].

        2. Let value be the result of converting idlValue to a JavaScript value.

        3. Perform ! CreateDataPropertyOrThrow(O, key, value).

        Recall that if member has a default value, then key will always exist in V.

  4. 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):

  1. Let S be the result of calling ? ToString(V).

  2. If S is not one of E’s enumeration values, then throw a TypeError.

  3. 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:

  1. 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 a TypeError.

  2. 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 null value.

A JavaScript value V is converted to an IDL nullable type T? value (where T is the inner type) as follows:

  1. 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 type T? value null.

  2. Otherwise, if V is undefined, and T includes undefined, return the unique undefined value.

  3. Otherwise, if V is null or undefined, then return the IDL nullable type T? value null.

  4. 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:

  1. If the IDL nullable type T? value is null, then the JavaScript value is null.

  2. 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:

  1. If V is not an Object, throw a TypeError.

  2. Let method be ? GetMethod(V, %Symbol.iterator%).

  3. If method is undefined, throw a TypeError.

  4. 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:

  1. Let n be the length of S.

  2. Let A be a new Array object created as if by the expression [].

  3. Initialize i to be 0.

  4. While i < n:

    1. Let V be the value in S at index i.

    2. Let E be the result of converting V to a JavaScript value.

    3. Let P be the result of calling ! ToString(i).

    4. Perform ! CreateDataPropertyOrThrow(A, P, E).

    5. Set i to i + 1.

  5. 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:

  1. Let iteratorRecord be ? GetIteratorFromMethod(iterable, method).

  2. Initialize i to be 0.

  3. Repeat

    1. Let next be ? IteratorStepValue(iteratorRecord).

    2. 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.

    3. Initialize Si to the result of converting next to an IDL value of type T.

    4. 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:

  1. If O is not an Object, throw a TypeError.

  2. Let result be a new empty instance of record<K, V>.

  3. Let keys be ? O.[[OwnPropertyKeys]]().

  4. For each key of keys:

    1. Let desc be ? O.[[GetOwnProperty]](key).

    2. If desc is not undefined and desc.[[Enumerable]] is true:

      1. Let typedKey be key converted to an IDL value of type K.

      2. Let value be ? Get(O, key).

      3. Let typedValue be value converted to an IDL value of type V.

      4. Set result[typedKey] to typedValue.

        Note: It’s possible that typedKey is already in result, if K is USVString and key contains unpaired surrogates.

  5. Return result.

An IDL record<…> value D is converted to a JavaScript value as follows:

  1. Let result be OrdinaryObjectCreate(%Object.prototype%).

  2. For each keyvalue of D:

    1. Let jsKey be key converted to a JavaScript value.

    2. Let jsValue be value converted to a JavaScript value.

    3. Let created be ! CreateDataProperty(result, jsKey, jsValue).

    4. Assert: created is true.

  3. 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:

  1. Let promiseCapability be ? NewPromiseCapability(%Promise%).

  2. Perform ? Call(promiseCapability.[[Resolve]], undefined, « V »).

  3. 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:

  1. Let constructor be realm.[[Intrinsics]].[[%Promise%]].

  2. 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:

  1. Let value be the result of converting x to a JavaScript value.

  2. Let constructor be realm.[[Intrinsics]].[[%Promise%]].

  3. Let promiseCapability be ? NewPromiseCapability(constructor).

  4. Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »).

  5. 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:

  1. Let constructor be realm.[[Intrinsics]].[[%Promise%]].

  2. Let promiseCapability be ? NewPromiseCapability(constructor).

  3. Perform ! Call(promiseCapability.[[Reject]], undefined, « r »).

  4. Return promiseCapability.

To resolve a Promise<T> p with x (a value of type T), perform the following steps:

  1. If x is not given, then let it be the undefined value.

  2. Let value be the result of converting x to a JavaScript value.

  3. Perform ! Call(p.[[Resolve]], undefined, « 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:

  1. Perform ! Call(p.[[Reject]], undefined, « r »).

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:

  1. Let onFulfilledSteps be the following steps given argument V:

    1. Let value be the result of converting V to an IDL value of type T.

    2. 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.

    3. Return result, converted to a JavaScript value.

  2. Let onFulfilled be CreateBuiltinFunction(onFulfilledSteps, « »):

  3. Let onRejectedSteps be the following steps given argument R:

    1. Let reason be the result of converting R to an IDL value of type any.

    2. 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.

    3. Return result, converted to a JavaScript value.

  4. Let onRejected be CreateBuiltinFunction(onRejectedSteps, « »):

  5. Let constructor be promise.[[Promise]].[[Realm]].[[Intrinsics]].[[%Promise%]].

  6. Let newCapability be ? NewPromiseCapability(constructor).

    Note: Not all callers will use the returned Promise. Implementations might wish to avoid creating newCapability in those cases.

  7. Perform PerformPromiseThen(promise.[[Promise]], onFulfilled, onRejected, newCapability).

  8. 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:

  1. Return the result of reacting to promise:

    • If promise was fulfilled with value v, then:

      1. 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:

  1. Return the result of reacting to promise:

    • If promise was rejected with reason r, then:

      1. 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:

  1. Let fullfilledCount be 0.

  2. Let rejected be false.

  3. Let rejectionHandlerSteps be the following steps given arg:

    1. If rejected is true, abort these steps.

    2. Set rejected to true.

    3. Perform failureSteps given arg.

  4. Let rejectionHandler be CreateBuiltinFunction(rejectionHandlerSteps, « »):

  5. Let total be promises’s size.

  6. If total is 0, then:

    1. Queue a microtask to perform successSteps given « ».

    2. Return.

  7. Let index be 0.

  8. Let result be a list containing total null values.

  9. For each promise of promises:

    1. Let promiseIndex be index.

    2. Let fulfillmentHandler be the following steps given arg:

      1. Set result[promiseIndex] to arg.

      2. Set fullfilledCount to fullfilledCount + 1.

      3. If fullfilledCount equals total, then perform successSteps given result.

    3. Let fulfillmentHandler be CreateBuiltinFunction(fulfillmentHandler, « »):

    4. Perform PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler).

    5. 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:

  1. Let promise be a new promise of type Promise<sequence<T>> in realm.

  2. Let successSteps be the following steps, given results:

    1. Resolve promise with results.

  3. Let failureSteps be the following steps, given reason:

    1. Reject promise with reason.

  4. Wait for all with promises, given successSteps and failureSteps.

  5. 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.

To mark as handled a 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:

  1. Let realm be this's relevant realm.

  2. Let taskSource be some appropriate task source.

  3. If ms is NaN, let ms be +0; otherwise let ms be the maximum of ms and +0.

  4. Let p be a new promise in realm.

  5. Run the following steps in parallel:

    1. Wait ms milliseconds.

    2. Queue a task on taskSource to resolve p.

  6. 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:

  1. Let realm be this's relevant realm.

  2. Let taskSource be some appropriate task source.

  3. If ms is NaN, return a promise rejected with a TypeError in realm.

  4. If ms < 0, return a promise rejected with a RangeError in realm.

  5. Let p be a new promise in realm.

  6. Run the following steps in parallel:

    1. Wait ms milliseconds.

    2. Queue a task on taskSource to resolve p.

  7. 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:

  1. Let realm be this's relevant realm.

  2. Let taskSource be some appropriate task source.

  3. If ms is NaN, let ms be +0; otherwise let ms be the maximum of ms and +0.

  4. Let p be a new promise in realm.

  5. React to promise:

    • If promise was fulfilled with value v, then:

      1. Run the following steps in parallel:

        1. Wait ms milliseconds.

        2. Queue a task on taskSource to resolve p with v.

    • If promise was rejected with reason r, then:

      1. Run the following steps in parallel:

        1. Wait ms milliseconds.

        2. Queue a task on taskSource to reject p with r.

  6. 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:

  1. Return this's ready promise.

To create an Environment object in a realm realm, perform the following steps:

  1. Let taskSource be some appropriate task source.

  2. Let environment be new Environment object in realm.

  3. Set environment’s ready promise to a new promise in realm.

  4. Run the following steps in parallel:

    1. Do some asynchronous work.

    2. If environment becomes ready successfully, then queue a task on taskSource to resolve environment’s ready promise.

    3. If environment fails to become ready, then queue a task on taskSource to reject environment’s ready promise with a "NetworkError" DOMException.

  5. 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:

  1. Let taskSource be some appropriate task source.

  2. If this method was not invoked as a result of explicit user action, return a promise rejected with a "SecurityError" DOMException.

  3. If the document’s mode of operation is standalone, return a promise rejected with a "NotSupportedError" DOMException.

  4. Let promise be a new promise.

  5. Let info be the result of getting a web application’s metadata.

  6. Run the following steps in parallel:

    1. 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.

      1. 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.

      2. Otherwise, queue a task on taskSource to resolve promise.

  7. 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:

  1. Let responsePromises be « ».

  2. For each url of urls:

    1. Let p be the result of calling fetch() with url.

    2. Append p to responsePromises.

  3. Let p be the result of getting a promise to wait for all with responsePromises.

  4. 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:

  1. If the union type includes undefined and V is undefined, then return the unique undefined value.

  2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.

  3. Let types be the flattened member types of the union type.

  4. If V is null or undefined, then:

    1. If types includes a dictionary type, then return the result of converting V to that dictionary type.

  5. If V is a platform object, then:

    1. If types includes an interface type that V implements, then return the IDL value that is a reference to the object V.

    2. If types includes object, then return the IDL value that is a reference to the object V.

  6. If V is an Object, V has an [[ArrayBufferData]] internal slot, and IsSharedArrayBuffer(V) is false, then:

    1. If types includes ArrayBuffer, then return the result of converting V to ArrayBuffer.

    2. If types includes object, then return the IDL value that is a reference to the object V.

  7. If V is an Object, V, has an [[ArrayBufferData]] internal slot, and IsSharedArrayBuffer(V) is true, then:

    1. If types includes SharedArrayBuffer, then return the result of converting V to SharedArrayBuffer.

    2. If types includes object, then return the IDL value that is a reference to the object V.

  8. If V is an Object and V has a [[DataView]] internal slot, then:

    1. If types includes DataView, then return the result of converting V to DataView.

    2. If types includes object, then return the IDL value that is a reference to the object V.

  9. If V is an Object and V has a [[TypedArrayName]] internal slot, then:

    1. 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.

    2. If types includes object, then return the IDL value that is a reference to the object V.

  10. If IsCallable(V) is true, then:

    1. If types includes a callback function type, then return the result of converting V to that callback function type.

    2. If types includes object, then return the IDL value that is a reference to the object V.

  11. If V is an Object, then:

    1. If types includes a sequence type, then

      1. Let method be ? GetMethod(V, %Symbol.iterator%).

      2. If method is not undefined, return the result of creating a sequence of that type from V and method.

    2. If types includes a frozen array type, then

      1. Let method be ? GetMethod(V, %Symbol.iterator%).

      2. If method is not undefined, return the result of creating a frozen array of that type from V and method.

    3. If types includes a dictionary type, then return the result of converting V to that dictionary type.

    4. If types includes a record type, then return the result of converting V to that record type.

    5. If types includes a callback interface type, then return the result of converting V to that callback interface type.

    6. If types includes object, then return the IDL value that is a reference to the object V.

  12. If V is a Boolean, then:

    1. If types includes boolean, then return the result of converting V to boolean.

  13. If V is a Number, then:

    1. If types includes a numeric type, then return the result of converting V to that numeric type.

  14. If V is a BigInt, then:

    1. If types includes bigint, then return the result of converting V to bigint

  15. If types includes a string type, then return the result of converting V to that type.

  16. If types includes a numeric type and bigint, then return the result of converting V to either that numeric type or bigint.

  17. If types includes a numeric type, then return the result of converting V to that numeric type.

  18. If types includes boolean, then return the result of converting V to boolean.

  19. If types includes bigint, then return the result of converting V to bigint.

  20. Throw a TypeError.

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.

A JavaScript value V is converted to an IDL ArrayBuffer value by running the following algorithm:

  1. If V is not an Object, or V does not have an [[ArrayBufferData]] internal slot, then throw a TypeError.

  2. If IsSharedArrayBuffer(V) is true, then throw a TypeError.

  3. If the conversion is not to an IDL type associated with the [AllowResizable] extended attribute, and IsResizableArrayBuffer(V) is true, then throw a TypeError.

  4. 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:

  1. If V is not an Object, or V does not have an [[ArrayBufferData]] internal slot, then throw a TypeError.

  2. If IsSharedArrayBuffer(V) is false, then throw a TypeError.

  3. If the conversion is not to an IDL type associated with the [AllowResizable] extended attribute, and IsResizableArrayBuffer(V) is true, then throw a TypeError.

  4. 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:

  1. If V is not an Object, or V does not have a [[DataView]] internal slot, then throw a TypeError.

  2. If the conversion is not to an IDL type associated with the [AllowShared] extended attribute, and IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw a TypeError.

  3. If the conversion is not to an IDL type associated with the [AllowResizable] extended attribute, and IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw a TypeError.

  4. 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:

  1. Let T be the IDL type V is being converted to.

  2. 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.

  3. If the conversion is not to an IDL type associated with the [AllowShared] extended attribute, and IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw a TypeError.

  4. If the conversion is not to an IDL type associated with the [AllowResizable] extended attribute, and IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is true, then throw a TypeError.

  5. Return the IDL value of type T that is a reference to the same object as V.

The result of converting an IDL value of any buffer source type to a JavaScript value is the Object value that represents a reference to the same object that the IDL value represents.

To create an ArrayBuffer from a byte sequence bytes in a realm realm:
  1. Let jsArrayBuffer be ? AllocateArrayBuffer(realm.[[Intrinsics]].[[%ArrayBuffer%]], bytes’s length).

  2. Let arrayBuffer be the result of converting jsArrayBuffer to an IDL value of type ArrayBuffer.

  3. Write bytes into arrayBuffer.

  4. Return arrayBuffer.

To create a SharedArrayBuffer from a byte sequence bytes in a realm realm:
  1. Let jsSharedArrayBuffer be ? AllocateSharedArrayBuffer(realm.[[Intrinsics]].[[%SharedArrayBuffer%]], bytes’s length).

  2. Let sharedArrayBuffer be the result of converting jsSharedArrayBuffer to an IDL value of type SharedArrayBuffer.

  3. Write bytes into sharedArrayBuffer.

  4. Return sharedArrayBuffer.

To create one of the ArrayBufferView types from a byte sequence bytes in a realm realm:
  1. Assert: if the type is not DataView, then bytes’s length modulo the element size of that type is 0.

  2. Let arrayBuffer be the result of creating an ArrayBuffer from bytes in realm.

  3. Let jsArrayBuffer be the result of converting arrayBuffer to a JavaScript value.

  4. Let constructor be the appropriate constructor from realm.[[Intrinsics]] for the type of ArrayBufferView being created.

  5. Let jsView be ! Construct(constructor, « jsArrayBuffer »).

  6. Return the result of converting jsView into the given type.

To get a copy of the bytes held by the buffer source given a buffer source type instance bufferSource:
  1. Let jsBufferSource be the result of converting bufferSource to a JavaScript value.

  2. Let jsArrayBuffer be jsBufferSource.

  3. Let offset be 0.

  4. Let length be 0.

  5. If jsBufferSource has a [[ViewedArrayBuffer]] internal slot, then:

    1. Set jsArrayBuffer to jsBufferSource.[[ViewedArrayBuffer]].

    2. Set offset to jsBufferSource.[[ByteOffset]].

    3. Set length to jsBufferSource.[[ByteLength]].

  6. Otherwise:

    1. Assert: jsBufferSource is an ArrayBuffer or SharedArrayBuffer object.

    2. Set length to jsBufferSource.[[ArrayBufferByteLength]].

  7. If IsDetachedBuffer(jsArrayBuffer) is true, then return the empty byte sequence.

  8. Let bytes be a new byte sequence of length equal to length.

  9. For i in the range offset to offset + length − 1, inclusive, set bytes[ioffset] to GetValueFromBuffer(jsArrayBuffer, i, Uint8, true, Unordered).

  10. Return bytes.

The byte length of a buffer source type instance bufferSource is the value returned by the following steps:
  1. Let jsBufferSource be the result of converting bufferSource to a JavaScript value.

  2. If jsBufferSource has a [[ViewedArrayBuffer]] internal slot, then return jsBufferSource.[[ByteLength]].

  3. Return jsBufferSource.[[ArrayBufferByteLength]].

The underlying buffer of a buffer source type instance bufferSource is the value returned by the following steps:
  1. If bufferSource is a buffer type instance, then return bufferSource.

  2. Let jsBufferView be the result of converting bufferSource to a JavaScript value.

  3. Let jsBuffer be jsBufferView.[[ViewedArrayBuffer]].

  4. If IsSharedArrayBuffer(jsBuffer) is false, then return the result of converting jsBuffer to an IDL value of type ArrayBuffer.

  5. Return the result of converting jsBuffer to an IDL value of type SharedArrayBuffer.

To write a byte sequence bytes into a buffer type instance arrayBuffer, optionally given a startingOffset (default 0):
  1. Let jsArrayBuffer be the result of converting arrayBuffer to a JavaScript value.

  2. Assert: bytes’s lengthjsArrayBuffer.[[ArrayBufferByteLength]] − startingOffset.

  3. For i in the range startingOffset to startingOffset + bytes’s length − 1, inclusive, perform SetValueInBuffer(jsArrayBuffer, i, Uint8, bytes[i - startingOffset], true, Unordered).

To write a byte sequence bytes into an ArrayBufferView view, optionally given a startingOffset (default 0):
  1. Let jsView be the result of converting view to a JavaScript value.

  2. Assert: bytes’s lengthjsView.[[ByteLength]] − startingOffset.

  3. Assert: if view is not a DataView, then bytes’s length modulo the element size of view’s type is 0.

  4. Let arrayBuffer be the result of converting jsView.[[ViewedArrayBuffer]] to an IDL value of type ArrayBuffer.

  5. Write bytes into arrayBuffer with startingOffset set to jsView.[[ByteOffset]] + startingOffset.

Extreme care must be taken when writing specification text that writes into a buffer source type instance, as the underlying data can easily be changed by the script author or other APIs at unpredictable times. This is especially true if a 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.

To detach an ArrayBuffer arrayBuffer:
  1. Let jsArrayBuffer be the result of converting arrayBuffer to a JavaScript value.

  2. 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.

A buffer source type instance bufferSource is detached if the following steps return true:
  1. Let jsArrayBuffer be the result of converting bufferSource to a JavaScript value.

  2. If jsArrayBuffer has a [[ViewedArrayBuffer]] internal slot, then set jsArrayBuffer to jsArrayBuffer.[[ViewedArrayBuffer]].

  3. Return IsDetachedBuffer(jsArrayBuffer).

A buffer source type instance bufferSource is transferable if the following steps return true:
  1. Let jsArrayBuffer be the result of converting bufferSource to a JavaScript value.

  2. If jsArrayBuffer has a [[ViewedArrayBuffer]] internal slot, then set jsArrayBuffer to jsArrayBuffer.[[ViewedArrayBuffer]].

  3. If IsSharedArrayBuffer(jsArrayBuffer) is true, then return false.

  4. If IsDetachedBuffer(jsArrayBuffer) is true, then return false.

  5. If jsArrayBuffer.[[ArrayBufferDetachKey]] is not undefined, then return false.

  6. Return true.

To transfer an ArrayBuffer arrayBuffer, optionally given a realm targetRealm:
  1. Let jsArrayBuffer be the result of converting arrayBuffer to a JavaScript value.

  2. If IsDetachedBuffer(jsArrayBuffer) is false, then throw a TypeError.

  3. Let arrayBufferData be jsArrayBuffer.[[ArrayBufferData]].

  4. Let arrayBufferByteLength be jsArrayBuffer.[[ArrayBufferByteLength]].

  5. Perform ? DetachArrayBuffer(jsArrayBuffer).

  6. If targetRealm is not given, let targetRealm be the current realm.

  7. Let jsTransferred be ? AllocateArrayBuffer(targetRealm.[[Intrinsics]].[[%ArrayBuffer%]], 0).

  8. Set jsTransferred.[[ArrayBufferData]] to arrayBufferData.

  9. Set jsTransferred.[[ArrayBufferByteLength]] to arrayBufferByteLength.

  10. Return the result of converting jsTransferred to an IDL value of type ArrayBuffer.

This will throw an exception under any of the following circumstances:
  • 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:

  1. Let values be the result of converting V to IDL type sequence<T>.

  2. 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:

  1. Let array be the result of converting the sequence of values of type T to a JavaScript value.

  2. Perform ! SetIntegrityLevel(array, "frozen").

  3. 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:

  1. Let values be the result of creating a sequence of type sequence<T> from iterable and method.

  2. 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.

The backing list for an observable array attribute in the JavaScript binding, given a platform object obj and an attribute attribute, is the list returned by the following algorithm:
  1. Assert: obj implements an interface with the regular attribute attribute.

  2. Let oa be obj’s backing observable array exotic object for attribute.

  3. 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.

The following IDL fragment demonstrates the possible combinations of the [AllowResizable] and [AllowShared] extended attribute:
[Exposed=Window]
interface ExampleBufferFeature {
  undefined writeInto(ArrayBufferView dest);
  undefined writeIntoResizable([AllowResizable] ArrayBufferView dest);
  undefined writeIntoShared([AllowShared] ArrayBufferView dest);
  undefined writeIntoSharedResizable([AllowResizable, AllowShared] ArrayBufferView dest);
};

With this definition,

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

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:

  1. Assert: C is an interface member, interface mixin member, namespace member, partial interface, partial interface mixin, partial namespace, or interface mixin.

  2. Assert: H is an interface or null.

  3. If H is null, return C’s own exposure set.

  4. If C’s own exposure set is *, return H’s exposure set.

  5. If H’s exposure set is *, return C’s own exposure set.

  6. Return the intersection of C’s own exposure set and H’s exposure set.

To get the exposure set of a construct C, run the following steps:
  1. Assert: C is an interface, callback interface, namespace, interface member, interface mixin member, or namespace member.

  2. Let H be C’s host interface if C is an interface mixin member, or null otherwise.

  3. If C is an interface member, interface mixin member, or namespace member, then:

    1. If the [Exposed] extended attribute is specified on C, return the exposure set intersection of C and H.

    2. Set C to the interface, partial interface, interface mixin, partial interface mixin, namespace, or partial namespace C is declared on.

  4. If C is a partial interface, partial interface mixin, or partial namespace, then:

    1. If the [Exposed] extended attribute is specified on C, return the exposure set intersection of C and H.

    2. Set C to the original interface, interface mixin, or namespace definition of C.

  5. If C is an interface mixin, then:

    1. Assert: H is not null.

    2. If the [Exposed] extended attribute is specified on C, return the exposure set intersection of C and H.

    3. Set C to H.

  6. Assert: C is an interface, callback interface or namespace.

  7. Assert: The [Exposed] extended attribute is specified on C.

  8. 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.

An interface, callback interface, namespace, or member construct is exposed in a given realm realm if the following steps return true:
  1. 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.

  2. If realm’s settings object is not a secure context, and construct is conditionally exposed on [SecureContext], then return false.

  3. If realm’s settings object's cross-origin isolated capability is false, and construct is conditionally exposed on [CrossOriginIsolated], then return false.

  4. Return true.

An interface, callback interface, namespace, or member construct is conditionally exposed on a given extended attribute exposure condition if the following steps return true:
  1. Assert: construct is an interface, callback interface, namespace, interface member, interface mixin member, or namespace member.

  2. Let H be construct’s host interface if construct is an interface mixin member, or null otherwise.

  3. If construct is an interface member, interface mixin member, or namespace member, then:

    1. If the exposure condition extended attribute is specified on construct, then return true.

    2. Otherwise, set construct to be the interface, partial interface, interface mixin, partial interface mixin, namespace, or partial namespace construct is declared on.

  4. If construct is a partial interface, partial interface mixin, or partial namespace, then:

    1. If the exposure condition extended attribute is specified on construct, then return true.

    2. Otherwise, set construct to be the original interface, interface mixin, or namespace definition of construct.

  5. If construct is an interface mixin, then:

    1. If the exposure condition extended attribute is specified on construct, then return true.

    2. Otherwise, set construct to H.

  6. Assert: construct is an interface, callback interface or namespace.

  7. If the exposure condition extended attribute is specified on construct, then return true.

  8. 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:

  1. Any named properties will be exposed on an object in the prototype chain – the named properties object – rather than on the object itself.

  2. 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 undefined, as the shadowing variable property would already have been created before the assignment is evaluated.

If the [Global] extended attributes is used on an interface, then:

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:

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

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 identifier that occurs directly after the “=” is 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 this value that is not an object that implements the interface on which the attribute appears will be ignored.

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.

The following IDL fragment defines a namespace and an interface which uses [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 is converted to the IDL type, it will be handled differently from its default handling. Instead of being stringified to "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 null is a valid value of that type.

See § 3.2.10 DOMString for the specific requirements that the use of [LegacyNullToEmptyString] entails.

The following IDL fragment defines an interface that has one attribute whose type has the extended attribute, and one operation whose argument’s type has the extended attribute:
[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 null value assigned to the 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 identifiers that occur after the “=” are 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:

  1. the platform object on which the operation invocation or attribute access is being done,

  2. the identifier of the operation or attribute, and

  3. 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:

  1. Let maxarg be the length of the longest type list of the entries in S.

  2. Let n be the size of args.

  3. Initialize argcount to be min(maxarg, n).

  4. Remove from S all entries whose type list is not of length argcount.

  5. If S is empty, then throw a TypeError.

  6. Initialize d to −1.

  7. Initialize method to undefined.

  8. If there is more than one entry in S, then set d to be the distinguishing argument index for the entries of S.

  9. Initialize values to be an empty list, where each entry will be either an IDL value or the special value “missing”.

  10. Initialize i to 0.

  11. While i < d:

    1. Let V be args[i].

    2. 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.

    3. Let optionality be the value at index i in the list of optionality values of any entry in S.

    4. If optionality is “optional” and V is undefined, then:

      1. If the argument at index i is declared with a default value, then append to values that default value.

      2. Otherwise, append to values the special value “missing”.

    5. Otherwise, append to values the result of converting V to IDL type type.

    6. Set i to i + 1.

  12. If i = d, then:

    1. Let V be args[i].

      Note: This is the argument that will be used to resolve which overload is selected.

    2. 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.

    3. Otherwise: if V is null or undefined, and there is an entry in S that has one of the following types at position i of its type list,

      then remove from S all other entries.

    4. 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,

      then remove from S all other entries.

    5. 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,

      then remove from S all other entries.

    6. 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,

      then remove from S all other entries.

    7. 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,

      then remove from S all other entries.

    8. 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,

      then remove from S all other entries.

    9. 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,

      and after performing the following steps,

      1. Let method be ? GetMethod(V, %Symbol.iterator%).

      method is not undefined, then remove from S all other entries.

    10. 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,

      then remove from S all other entries.

    11. 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,

      then remove from S all other entries.

    12. 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,

      then remove from S all other entries.

    13. 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,

      then remove from S all other entries.

    14. Otherwise: if there is an entry in S that has one of the following types at position i of its type list,

      then remove from S all other entries.

    15. Otherwise: if there is an entry in S that has one of the following types at position i of its type list,

      then remove from S all other entries.

    16. Otherwise: if there is an entry in S that has one of the following types at position i of its type list,

      then remove from S all other entries.

    17. Otherwise: if there is an entry in S that has one of the following types at position i of its type list,