You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: index.bs
+126Lines changed: 126 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1524,6 +1524,132 @@ the interaction with garbage collection.
1524
1524
1525
1525
<h2 id="api-surface">JavaScript API Surface Concerns</h2>
1526
1526
1527
+
<h3>Choose the Appropriate WebIDL Construct for Data and Behavior (Dictionaries, Interfaces, and Namespaces)</h3>
1528
+
1529
+
Web APIs commonly pass around data and functionality using WebIDL. As a specification author, decide carefully whether
1530
+
to use a dictionary, an interface, or in rare cases, a namespace.
1531
+
1532
+
The goal is to ensure ergonomic, consistent APIs that feel natural to Web developers while avoiding pitfalls like "fake classes" or classes that provide no functionality.
1533
+
1534
+
Each construct has its own pros and cons, discussed below.
1535
+
1536
+
<h4>Use Dictionaries for “Configuration” or “Input-Only” Data</h4>
1537
+
1538
+
Choose a dictionary when the part of the API represents data that is transient or you need a configuration-style object or "options bag".
1539
+
1540
+
Dictionaries are ideal for when the data doesn't get stored or mutated; it's just used it at the time of the call.
1541
+
1542
+
For example, the `ShareData` member from Web Share:
1543
+
1544
+
```WebIDL
1545
+
dictionary ShareData {
1546
+
USVString title;
1547
+
USVString text;
1548
+
USVString url;
1549
+
};
1550
+
```
1551
+
1552
+
And how it's commonly used:
1553
+
1554
+
<pre class="highlight">
1555
+
const data = { "text": "Text being shared" };
1556
+
await navigator.share(data);
1557
+
</pre>
1558
+
1559
+
Dictionaries are easily extensible and makes it easy to add optional fields later as needed.
1560
+
Members of a dictionary are optional by default, but can be marked as `required` if needed.
1561
+
1562
+
Dictionaries are also highly idiomatic (i.e., natural to use in JavaScript). Passing `{ ... }` inline is the most natural way to supply configuration in JavaScript.
1563
+
1564
+
Dictionaries, because of how they are treated by user agents, are also relatively future-proof; accommodating new members gracefully, without breaking older code.
1565
+
1566
+
Dictionaries are best used for objects that don't need to be distigusied by type in their lifecycle (i.e., `instanceof` checks are mostly meaningless because it's always `Object`).
1567
+
1568
+
A key thing to know about dictionries is that they are "passed by value" to methods (i.e., they are copied) and that browsers engines strip unknown members when converting from JavaScript objects to a WebIDL reprensentation.
1569
+
This means that if a developer changing the value after it is passed into an API has no effect.
1570
+
1571
+
Again, taking the `ShareData` dictinary as an example:
1572
+
1573
+
```JS
1574
+
const data = {
1575
+
"text": "Text being shared",
1576
+
// Not in the dictionary, so removed by the browser
1577
+
"whatever": 123,
1578
+
};
1579
+
navigator.share(data);
1580
+
1581
+
// Changing this after calling .share() has no effect
1582
+
data.text = "New text";
1583
+
```
1584
+
1585
+
<h4>Choose an Interface for Functionality, State, and Identity</h4>
1586
+
1587
+
Intefaces are roughly equivalent to classes in JavaScript. Choose and an interface when a specificaiton need object with data that might also have — or eventually gain — methods, computed or readonly properties, or internal state or "slots".
1588
+
1589
+
Unlike dictrionaries, interfaces:
1590
+
1591
+
* provide the ability to check object's identity (i.e., one can check if it is an `instanceof` a particular class on the global scope),
1592
+
* can have need read-only properties,
1593
+
* can have state,
1594
+
* can exhibit side-effects on assignment.
1595
+
1596
+
Defining an interface also exposes it on the global scope, allowing for the specification of static methods. For example, the `canParse()` static method of the URL interface.
1597
+
1598
+
```JS
1599
+
if (URL.canParse(someURL)) {
1600
+
// Do stuff...
1601
+
}
1602
+
```
1603
+
1604
+
If the interface can holds data that is useful when serialized (e.g., `GeolocationPosition`), consider adding a `toJSON()` default method. Alternatively, if it holds binary data, one can add .toBlob() an so on.
1605
+
1606
+
This makes object natural to use with APIs. For example:
1607
+
1608
+
```JS
1609
+
const position = await new Promise((resolve, reject) => {
If warrented by the use cases, give the interface a constructor. Be mindful to not just add a constructor if a class has no state. Doing so is considered by practice by effectively creaeting a fake class.
1625
+
(see `DOMParser` or `DOMImplementation` as bad examples).
1626
+
1627
+
In such cases, prefer a static method on an existing object or, if absolutely necessary, mint a new namespace.
1628
+
1629
+
<h4>Choose a namespace to Avoid “Fake Classes” for Behavior-Only Utilities</h4>
1630
+
1631
+
A namespace is correct if everything is purely static and lacks a prototype (like the `Math`, `Intl`, `Atomics`, `Console` objects in JS).
1632
+
1633
+
If you only have one or two small static functions, a whole new namespace may be overkill. Attaching them to an existing object might be more idiomatic.
1634
+
1635
+
Conversely, a namespace that grows too large or too broad may need better organization or separate logical partitions.
1636
+
1637
+
<h4>"Pseudo-namespaces"</h4>
1638
+
1639
+
As WebIDL interfaces can have attributes, it is possible to create "pseudo-namespaces" by leveraging non-contructable interface as attributes.
1640
+
1641
+
A common example are all the attributes attaches to the navigator object. The navigator object has an interface definition (`Navigator`), which iteself contains other
1642
+
atttributes that gives access to further functionality through interface instances.
1643
+
1644
+
For example:
1645
+
1646
+
* `navigator.credentials` - The `CredentialsContainer` interface of the Credentials Management API.
1647
+
* `navigator.geolocation` - The `Geolocation` interface of the Geolocation specification.
1648
+
* `navigator.permissions` - The `Permissions` interface of the Permissions specification.
1649
+
1650
+
Psudo-namespaces are useful for when, as a spec author, you need access to "this" particular instance
1651
+
(e.g., where the properties of one instance may different from those of another browsing context).
1652
+
1527
1653
<h3 id="attributes-like-data">Attributes should behave like data properties</h3>
1528
1654
1529
1655
[[!WEBIDL]] attributes should act like simple JavaScript object properties.
0 commit comments