4

I'm not sure I get the logic behind the js implementation of optional chaining.

const a = {b:1}

1 > console.log(a?.c)     => undefined
2 > console.log(a?.c?.d)  => undefined
3 > console.log(a?.c.d)   => Uncaught TypeError: Cannot read property 'd' of undefined

everything make sense so long. Then:

4 > console.log(a?.c?.d.e) => undefined
5 > console.log(a?.c?.d.e.f.g) => undefined

Accessing a property of undefined throws an error (#3), but accessing an arbitrary amout of non existing nested properties after 2 optional chaining doesn't throw errors anymore.

alfredopacino
  • 2,979
  • 9
  • 42
  • 68
  • 1
    That's the whole idea. If you have a `?` after the last missing property, the rest of the expression works because it short-circuits. – Pointy Apr 07 '20 at 14:57
  • @Pointy then why does the example #3 throws an error? – alfredopacino Apr 07 '20 at 14:58
  • Because `a` is not null but `a.c` is `undefined` – Pointy Apr 07 '20 at 15:01
  • @alfredopacino because `a` is non-falsy. So you get `c` from it but you *do not have optional chaining*, so you do a *mandatory chain* (I guess that's the opposite of "optional") to get the concrete value `undefined` and try to get the property `d` from it. – VLAZ Apr 07 '20 at 15:01
  • 2
    You mark the place, where you are unsure, whether the property access works, with optional chaining. Take the case, where you are sure, that objects are either: `a = { b: { c: { d: "value" }}}` or `a = {}`. You say `a?.b.c.d`. If it's the first case, it goes to "value", if it's the second, it will simply notice, that the property access of `.b` doesn't exist (`undefined`), so it ignores everything afterwards, and returns `undefined`. However, if you have `a = { b: {}}`, then the property access for `b` isn't undefined, and it will evaluate the rest, which throws. – ASDFGerte Apr 07 '20 at 15:07
  • 1
    @ASDFGerte in other words, `a?.b` is `a || a.b` in "old syntax", so `a?.b.c` is `a || a.b.c` - if `a.b` is `undefined` there is nothing to stop the chaining. Whereas `a?.b?.c` would be `a || a.b || a.b.c` so you're safe from trying to fetch `.c` from `undefined`. – VLAZ Apr 07 '20 at 15:11
  • 2
    @alfredopacino maybe take a look at the short-circuiting section defined in the proposal: https://github.com/tc39/proposal-optional-chaining/#short-circuiting – Nick Parsons Apr 07 '20 at 15:13

1 Answers1

0

The comments on the question answer it correctly. Here's a clarification:

console.log(a.c)     // undefined
console.log(a.c.d)   // Uncaught TypeError: Cannot read property 'd' of undefined
console.log(a.c.d.e)   // Uncaught TypeError: Cannot read property 'd' of undefined
console.log(a.c?.d)  // undefined
console.log(a.c?.d.e) // undefined
console.log(a.c?.d.e.f.g) // undefined

You can see that evaluation always stops at c, since there is no property a.c. When it stops, if you have used the optional chaining operator (?.), it returns undefined, if not, it throws an error.

Note that this is a recent feature. For nodejs it appears in version 14, which is production-ready (LTS) as of 2020/10/27.

user1527225
  • 1,059
  • 9
  • 7