Skip to content
This repository was archived by the owner on Jan 25, 2022. It is now read-only.

Commit 014a8a7

Browse files
author
Dustin Savery
committed
[spec update] spec updates to refine the target of this proposal
1 parent b5cb08d commit 014a8a7

File tree

3 files changed

+899
-117
lines changed

3 files changed

+899
-117
lines changed

README.md

Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Current Stage:
77
## Authors
88
* Claude Pache (@claudepache)
99
* Gabriel Isenberg (@the_gisenberg)
10+
* Dustin Savery (@dustinsavery)
1011

1112
## Overview and motivation
1213
When looking for a property value that's deep in a tree-like structure, one often has to check whether intermediate nodes exist:
@@ -29,19 +30,6 @@ var street = user.address?.street
2930
var fooValue = myForm.querySelector('input[name=foo]')?.value
3031
```
3132
32-
The call variant of Optional Chaining is useful for dealing with interfaces that have optional methods:
33-
34-
```js
35-
iterator.return?.() // manually close an iterator
36-
```
37-
or with methods not universally implemented:
38-
```js
39-
if (myForm.checkValidity?.() === false) { // skip the test in older web browsers
40-
// form validation fails
41-
return;
42-
}
43-
```
44-
4533
## Prior Art
4634
The following languages implement the operator with the same general semantics as this proposal (i.e., 1) guarding against a null base value, and 2) short-circuiting application to the whole chain):
4735
* C#: [Null-conditional operator](https://msdn.microsoft.com/en-us/library/dn986595.aspx) — null-conditional member access or index, in read access.
@@ -58,7 +46,6 @@ The Optional Chaining operator is spelled `?.`. It may appear in three positions
5846
```javascript
5947
obj?.prop // optional static property access
6048
obj?.[expr] // optional dynamic property access
61-
func?.(...args) // optional function or method call
6249
```
6350
6451
### Notes
@@ -67,7 +54,7 @@ func?.(...args) // optional function or method call
6754
## Semantics
6855
6956
### Base case
70-
If the operand at the left-hand side of the `?.` operator evaluates to undefined or null, the expression evaluates to undefined. Otherwise the targeted property access, method or function call is triggered normally.
57+
If the operand at the left-hand side of the `?.` operator evaluates to undefined or null, the expression returns undefined or null respectively. Otherwise the targeted property is accessed normally.
7158
7259
Here are basic examples, each one followed by its desugaring. (The desugaring is not exact in the sense that the LHS should be evaluated only once.)
7360
```js
@@ -80,10 +67,6 @@ a == null ? undefined : a[x]
8067
a?.b()       // undefined if `a` is null/undefined
8168
a == null ? undefined : a.b() // throws a TypeError if `a.b` is not a function
8269
                            // otherwise, evaluates to `a.b()`
83-
84-
a?.()       // undefined if `a` is null/undefined
85-
a == null ? undefined : a() // throws a TypeError if `a` is neither null/undefined, nor a function
86-
            // invokes the function `a` otherwise
8770
```
8871
8972
### Short-circuiting
@@ -97,7 +80,7 @@ a == null ? undefined : a[++x]
9780
9881
### Long short-circuiting
9982
100-
In fact, short-circuiting, when triggered, skips not only the current property access, method or function call, but also the whole chain of property accesses, method or function calls directly following the Optional Chaining operator.
83+
In fact, short-circuiting, when triggered, skips not only the current property access, but also the whole chain of property accesses directly following the Optional Chaining operator.
10184
10285
```js
10386
a?.b.c(++x).d  // if `a` is null/undefined, evaluates to undefined. Variable `x` is not incremented.
@@ -116,8 +99,8 @@ Let’s call *Optional Chain* an Optional Chaining operator followed by a chain
11699
An Optional Chain may be followed by another Optional Chain.
117100
118101
```js
119-
a?.b[3].c?.(x).d
120-
a == null ? undefined : a.b[3].c == null ? undefined : a.b[3].c(x).d
102+
a?.b[3].c?.d(x)
103+
a == null ? undefined : a.b[3].c == null ? undefined : a.b[3].c.d(x)
121104
// (as always, except that `a` and `a.b[3].c` are evaluated only once)
122105
```
123106
@@ -134,37 +117,22 @@ That follows from the design choice of specifying the scope of short-circuiting
134117
135118
Note that, whatever the semantics are, there is no practical reason to use parentheses in that position anyway.
136119
137-
### Optional deletion
138-
139-
Because the `delete` operator is very liberal in what it accepts, we have that feature for free:
140-
```js
141-
delete a?.b
142-
// delete (a == null ? undefined : a.b) // that *would* work if `? :` could return a Reference...
143-
a == null ? undefined : delete a.b // this is what we get, really
144-
```
145-
146120
## Not supported
147121
148-
Although they could be included for completeness, the following are not supported due to lack of real-world use cases or other compelling reasons; see [Issue # 22](https://github.com/tc39/proposal-optional-chaining/issues/22) and [Issue #54](https://github.com/tc39/proposal-optional-chaining/issues/54) for discussion:
122+
Although they could be included for completeness, the following are not supported due to complexity, lack of real-world use cases, or other compelling reasons:
149123
124+
* optional function execution: `a?.()`
150125
* optional construction: `new a?.()`
151126
* optional template literal: ``a?.`{b}` ``
152127
* constructor or template literals in/after an Optional Chain: `new a?.b()`, ``a?.b`{c}` ``
153-
154-
The following is not supported, although it has some use cases; see [Issue #18](//github.com/tc39/proposal-optional-chaining/issues/18) for discussion:
155-
156-
* optional property assignment: `a?.b = c`
128+
* optional assignment: `a?.b?.c = x`
157129
158130
All the above cases will be forbidden by the grammar or by static semantics so that support might be added later.
159131
160132
## FAQ
161133
162-
[TODO: to be completed. In particular, discuss specific criticisms around long short-circuiting.]
163-
164-
165134
<dl>
166135
167-
168136
<dt>obj?.[expr] and func?.(arg) look ugly. Why not use obj?[expr] and func?(arg) as does &lt;language X>?
169137
170138
<dd>
@@ -174,22 +142,10 @@ We don’t use the `obj?[expr]` and `func?(arg)` syntax, because of the difficul
174142
Alternative syntaxes for those two cases each have their own flaws; and deciding which one looks the least bad is mostly a question of personal taste. Here is how we made our choice:
175143
176144
* pick the best syntax for the `obj?.prop` case, which is expected to occur most often;
177-
* extend the use of the recognisable `?.` sequence of characters to other cases: `obj?.[expr]`, `func?.(arg)`.
145+
* extend the use of the recognisable `?.` sequence of characters to other cases: `obj?.[expr]`.
178146
179147
As for &lt;language X>, it has different syntactical constraints than JavaScript because of &lt;some construct not supported by X or working differently in X>.
180148
181-
182-
183-
<dt>Why does (null)?.b evaluate to undefined rather than null?
184-
185-
<dd>
186-
187-
Neither `a.b` nor `a?.b` is intended to preserve arbitrary information on the base object `a`, but only to give information about the property `"b"` of that object. If a property `"b"` is absent from `a`, this is reflected by `a.b === undefined` and `a?.b === undefined`.
188-
189-
In particular, the value `null` is considered to have no properties; therefore, `(null)?.b` is undefined.
190-
191-
192-
193149
<dt>Why do you want long short-circuiting?</dt>
194150
195151
<dd>

0 commit comments

Comments
 (0)