Optional Chaining (But reading this article is not optional…😉)

Hey Folks!!!

Today we are going to explore a new topic of modern javascript (polyfills are always there 😅)

Optional chaining (‘?.’)

So javascript is very clever but at some point , it is just a piece of code which don’t know what to do (it occurs rarely 😎)

So there is a problem named “non-existing-property”… Wait what is this?? 😕…let’s dive into an example

As an example, let’s say we have user objects that hold the information about our users.

Most of our users have addresses in user.address property, with the street user.address.street, but some did not provide them.

In such case, when we attempt to get user.address.street, and the user happens to be without an address, we get an error:

let user = {}; // a user without "address" propertyalert(user.address.street); // Error!

That’s the expected result. JavaScript works like this. As user.address is undefined, an attempt to get user.address.street fails with an error.

In many practical cases we’d prefer to get undefined instead of an error here (meaning “no street”).

…And another example. In the web development, we can get an object that corresponds to a web page element using a special method call, such as document.querySelector('.elem'), and it returns null when there’s no such element.

// document.querySelector('.elem') is null if there's no element let html = document.querySelector('.elem').innerHTML; // error if it's null

But Wait there is already a solution for this (using If Condition Or && operator😊)
Let us see an example using the && operator:

let user = {}; // user has no addressalert( user.address && user.address.street && user.address.street.name ); // undefined (no error)

AND’ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn’t ideal.

As you can see, property names are still duplicated in the code. E.g. in the code above, user.address appears three times.

That’s why the optional chaining ?. was added to the language. To solve this problem once and for all!

The optional chaining ?. stops the evaluation if the part before ?. is undefined or null and returns that part.

Another example ?😛

So let us take same example (👆)

Here’s the safe way to access user.address.street using ?.:

let user = {}; // user has no addressalert( user?.address?.street ); // undefined (no error)

The code is short and clean, there’s no duplication at all.

Reading the address with user?.address works even if user object doesn’t exist:

let user = null;alert( user?.address ); // undefined
alert( user?.address.street ); // undefined

Please note: the ?. syntax makes optional the value before it, but not any further. But there is a catch (😧)

The variable before ?. must be declared

If there’s no variable user at all, then user?.anything triggers an error:

// ReferenceError: user is not defined
user?.address;

The variable must be declared (e.g. let/const/var user or as a function parameter). The optional chaining works only for declared variables.

Other variants: ?.(), ?.[]

The optional chaining ?. is not an operator, but a special syntax construct, that also works with functions and square brackets.

For example, ?.() is used to call a function that may not exist.

In the code below, some of our users have admin method, and some don’t:

let userAdmin = {
admin() {
alert("I am admin");
}
};
let userGuest = {};userAdmin.admin?.(); // I am adminuserGuest.admin?.(); // nothing (no such method)

Here, in both lines we first use the dot (object.admin) to get admin property, because the user object must exist, so it’s safe read from it.

Then ?.() checks the left part: if the admin function exists, then it runs (that’s so for userAdmin). Otherwise (for userGuest) the evaluation stops without errors.

The ?.[] syntax also works, if we’d like to use brackets [] to access properties instead of dot .. Similar to previous cases, it allows to safely read a property from an object that may not exist.

let person1 = {
firstName: "John"
};
let person2 = null; // Imagine, we couldn't authorize the userlet key = "firstName";alert( person1?.[key] ); // John
alert( person2?.[key] ); // undefined
alert( person1?.[key]?.something?.not?.existing); // undefined

Also we can use ?. with delete:

delete person?.name; // delete person.name if person exists

Summary

obj.val?.prop
obj.val?.[expr]
obj.arr?.[index]
obj.func?.(args)

Thank you for reading 🙌

Clap! if this was useful for you 👋

Working as a full time Front-End developer & also searching web for some cool stuff.