This is a proposal for introducing Optional Chaining feature (aka Existential Operator, aka Null Propagation) in ECMAScript).
When looking for a property value deeply in a tree structure, one has often to check whether intermediate nodes exist:
var street = user.address && user.address.street
Also, many API return either an object or null/undefined, and one may want to extract a property from the result only when it is not null:
var fooInput = myForm.querySelector('input[name=foo]') var fooValue = fooInput ? fooInput.value : undefined
The Optional Chaining Operator allows to handle many of those cases without repeating yourself and/or assigning intermediate results in temporary variables:
var street = user.address?.street var fooValue = myForm.querySelector('input[name=foo]')?.value
The operator is spelt
?. and may be used at the following positions:
obj?.prop // optional property access obj?.[expr] // ditto func?.(...args) // optional function or method call new C?.(...args) // optional constructor invocation
In order to allow
foo?.3:0to be parsed as
foo ? .3 : 0rather than
foo ?. 3 : 0, a simple lookahead is added at the level of the lexical grammar (the
?.token should not be followed by a decimal digit).
We don’t use the
func?(...arg)syntax, because of the difficulty for the parser to distinguish those forms from the conditional operator, e.g.
func?(x - 2) + 3 :1.
(The explanations here are optimised for the human mind. For a more machine-friendly version, look at the spec text.)
Base case. If the expression at the left-hand side of the
?. operator evaluates to undefined or null, its right-hand side is not evaluated and the whole expression returns undefined.
a?.b // undefined if a is null/undefined, a.b otherwise a?.[++x] // If a evaluates to null/undefined, the variable x is *not* incremented.
Short-circuiting. A value of undefined produced by the
?. operator is propagated without further evaluation to an entire chain of property accesses, method calls, constructor invocations, etc. (or, in spec parlance, a Left-Hand-Side Expression).
a?.b.c().d // undefined if a is null/undefined, a.b.c().d otherwise. // NB: If a is not null/undefined, and a.b is nevertheless undefined, // short-circuiting does *not* apply
Free grouping. Use of parentheses for mere grouping does not stop short-circuiting.
(a?.b).c().d // equivalent to: a?.b.c().d
Use in write context. The
?. operator may also be used for optional property writing and deletion:
a?.b = 42 // does nothing if a is null/undefined, equivalent to a.b = 42 otherwise delete a?.b // no-op if a is null/undefined
Technically the semantics are enforced by introducing a special Reference, called Nil, which is propagated without further evaluation through left-hand side expressions (property accesses, method calls, etc.), and which dereferences to undefined (or to /dev/null in write context).
See the spec text for more details.