Optional chaining helps to avoid "undefined is not a function" exceptions

Published at
Updated at
Reading time
3 min

This post is part of my Today I learned series in which I share all my learnings regarding web development.

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

Before we dive in, let's have a look at the new optional chaining feature very quickly.

This new JavaScript 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".

#

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 ?.().

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, which will help to avoid a few undefined is not a function exceptions.

That said, exception are there 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.

Related Topics

See null comment.