?? 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 aschild
wasundefined
secondChild
,thirdChild
andfourthChild
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.