?? Nullish coalescing & Optional chaining ?.

?? Nullish coalescing & Optional chaining ?.

Javascript Sucks! It really really does at times. Take a look at the difference between the books ‘The Definitive Guide’ and the ‘the best bits’ 😁 I joke, of course, but some portions of it are just annoying.

It’s loose and simple way, is it’s strength and it’s weakness, but with each new feature from the latest ES++ range comes new means to clean up your code and hopefully stop shooting your feet!
The below new operators come from ES2020, the 11th edition.

Operators with ? in them can be a bit confusing if you’ve never seen them and also they are hard to search for. How do you search for ? if you don’t know the operator name? So this is here for my own bookmarking as well as a reference for others. First up we have the ??

?? is the Nullish Coalescing operator

What’s its purpose, to make getting expected true/false values back where it would seem normal to do so! What do I mean, well normally if you want something to be false you’d make it false. Or you’d expect null/undefined to be false.

But under normal circumstances, JS isn’t like that. I’m not going to go into the falsy/truthiness of JS, but to suffice to say that the ?? allows for default values such as 0 or an empty string to be valid values, rather than being false.

const textSetToAnEmptyString = "";
const DEAFAULT_TEXT = "This is the default";

const myText = textSetToAnEmptyString ?? DEAFAULT_TEXT;
console.log(myText); // ""

const myTextOldWay = textSetToAnEmptyString || DEAFAULT_TEXT;
console.log(myTextOldWay); // "This is the default" - probably not what you wanted

As can be seen if the text is set to an empty string which is a valid value, with the ?? operator it remains as an empty string, which is exactly what you’d wish.

But if you wished to use the || operator then the empty string will be changed as “” is considered false in JS land.

?. is the Optional chaining operator

Looking into this new feature, it is REALLY great.
Checking if a value exists in some nested object for JS is yet another of those painful items. Not that’s it hard to do, but it’s such bloated code.
So this is simplest to show via code

// set up an empty object
const obj = {};
const foo = obj.child;  // foo will be undefined - No error
const fooError = obj.child.secondChild;  // Error - can't access secondChild from an undefined value
const fooTwo = obj.child?.secondChild; // fooTwo will be undefined - no error
const fooThree = obj.child?.secondChild.thirdChild; // fooThree will be undefined - no error
const fooFour = obj.child?.secondChild.thirdChild.fourthChild; // undefined - no error

What’s going on with fooThree and fooFour???

Well the ?. operator is short circuiting when it goes to assign a value to to fooThree and fooFour.

  • Looks at obj – which is a valid object
  • looks for child, and JS being the way it is doesn’t complain, and returns undefined (as it does not exist)
  • ?. check now means that it will go no further as child was undefined
  • secondChild, thirdChild and fourthChild do not get looked at/processed due to the short circuiting of process

Also works on methods 👍

const myFunc = () => { return "WOOO" };

const foo = {
  methodX : myFunc
}

const message = foo.methodX(); // "WOOO"
const message2 = foo.methodY(); // Error - methodY does not exist
const message3 = foo.methodY?.(); // undefined and carries on

// The ?. syntax will also work in the same way with arrays
// such as myArray?.[12] 👍

Multiple ?.

In the above child isn’t defined, but what would happen if it was defined?

const obj = {};
obj.child = {}; // Set child to an empty object
const foo = obj.child?.secondChild; // undefined - no error
const fooTwo = obj.child?.secondChild.thirdChild; // Error - can't access thirdChild from an undefined value
const fooThree = obj.child?.secondChild?.thirdChild; // undefined - no error

Here we needed to insert a second ?., this will check that secondChild is set before moving on. So for fooTwo there is an error as thirdChild can’t be accessed from undefined, but fooThree is ok as it doesn’t get to thirdChild due to the short circuiting.

Combos!

Both the above are powerful tools and even better is that they can be combined!
Let’s say you

let myMap = new Map();
myMap.set("foo", {name: "baz", description: "" });
myMap.set("bar", {name: "baz" });

let descriptionFoo = myMap.get("foo")?.description ?? "description not set"; // output is ""
let descriptionFooOld = myMap.get("foo")?.description || "description not set"; // Output is "description not set" - not what you'd wish for as it has been set
let descriptionBar = myMap.get("bar")?.description ?? "description not set"; // output is "description not set" as it wasn't set

Hopefully the above will give you some ideas of where to use these new operators. I’m sure as I go through some old code I’ll see better examples on where to use them.

Leave a Reply

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.