Published at
Updated at
Reading time
3min
This post is part of my Today I learned series in which I share all my web development learnings.

I was reading the MDN docs for optional chaining and came across a fact I didn't know about it.

Before we get into my learning, let's have a brief look at the new optional chaining JavaScript feature. The language addition allows developers to access optional values that are nested deeply inside of an object in a safer way.

The process of accessing a deeply nested object property can be very tedious. It could be that the object does not have the structure you expect or that it doesn't define the values you're looking for. To avoid thrown exceptions developers had to check every single property for its existence before accessing the deeply nested property.

The new ?. syntax helps developers to access properties in a safe manner even if the object structure is different than expected. Let's have a look at an example:

// object coming from an API, a library or anything you don't control
const someObject = { foo: { bar: { baz: 'someValue' } } };

// old way to access foo.bar.baz 
// -> check all properties to avoid throwing an exception
if (someObject.foo && someObject.foo.bar && someObject.foo.bar.baz) {
  console.log(someObject.foo.bar.baz);
} else {
  console.log('noValue');
}

// new way to access foo.bar.baz
console.log(someObject.foo?.bar?.baz || 'noValue'); 
// ๐Ÿ‘† logs 'someValue' because `someObject.foo.bar.baz` is defined
            
console.log(someObject.foo?.bar?.doesNotExist || 'noValue');
// ๐Ÿ‘† logs 'noValue' because `someObject.foo.bar.doesNotExist` is not defined
console.log(someObject.doesNotExist?.foo?.bar || 'noValue');
// ๐Ÿ‘† logs 'noValue' because `someObject.doesNotExist` is not defined
//    it does not throw an exception for accessing `foo` of `doesNotExist`

The optional chaining feature proposal is currently on stage 4 of the ECMAscript proposal process which means it will be part of the EcmaScript 2020 additions. Chrome already implements it behind the feature flag "Experimental JavaScript".

Edit: It's cross-browser supported now.

Execute methods if they exist and return undefined otherwise

What I didn't know was that this proposal also includes a mechanism to execute object methods that potentially are undefined using the funny looking syntax ?.().

const someObject = { foo() { return 'someValue'; } };

// execute functions with `?.()` to not throw an exception
// in case it is not defined
console.log(someObject.foo?.() || 'notDefined'); 
// ๐Ÿ‘† logs 'someValue' because `someObject.foo?.()` returns 'someValue'

console.log(someObject.bar?.() || 'notDefined');
// ๐Ÿ‘† logs 'notDefined' because `someObject.bar?.()` returns undefined
//    instead of throwing an exception

In my opinion, optional chaining and its optional function execution is a very welcome language addition, that will help to avoid a few undefined is not a function exceptions.

That said, exceptions exist for a reason and developers should be very careful with these new features that make exceptions "disappear". If optional chaining is used very often and/or only used to hide exceptions, it's probably a hint to rethink the overall application architecture.

I can't wait for optional chaining to be supported across browsers. If you want to use it today, babel has you covered. And with that โ€“ have fun, friends! ๐Ÿ‘‹

Edited: As TheIncorrigible1 pointed out on Reddit optional chaining works perfectly together with Nullish Coalescing which you might want to check out, too.

If you enjoyed this article...

Join 5.5k readers and learn something new every week with Web Weekly.

Web Weekly โ€” Your friendly Web Dev newsletter
Reply to this post and share your thoughts via good old email.
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles