Optional chaining helps to avoid "undefined is not a function" exceptions
- Published at
- Updated at
- Reading time
- 3min
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.
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.
Join 5.5k readers and learn something new every week with Web Weekly.