Explain Codes LogoExplain Codes Logo

Is there a null-coalescing (Elvis) operator or safe navigation operator in JavaScript?

javascript
prompt-engineering
optional-chaining
nullish-coalescing
Alex KataevbyAlex Kataev·Nov 23, 2024
TLDR

For default values in null or undefined cases, use JavaScript's nullish coalescing operator (??):

// No potatoes for dinner? Well, we always have `defaultFood` in the fridge. const dinner = potatoes ?? 'defaultFood';

For safely accessing nested properties, use JavaScript's optional chaining operator (?.):

// Will Bob's dog speak? Find out without causing a scene if the pet doesn't exist const sound = user?.pet?.speak;

A closer look at nullish vs falsy values

The ?? operator shines when distinguishing between nullish and falsy values. Nullish values are fewer - only null and undefined. However, Falsy drags more elements into the club:

  • null
  • undefined
  • false
  • 0
  • '' or ""
  • NaN

Crucially, ?? only defaults to its right-hand side for nullish values, while || will do so for all falsy values:

// Sorry, NULL, your name is not on the guest list. // Trust me, ZERO tried to get in too - zero success. const alternativeFact = zeroOrNull ?? 'Invited';

This matters if you're dealing with 0, false, and "" where you don't want the truthy default value to override falsy-but-legitimate values.

Safely navigating your way into nested property checks

Nested properties often feel like walking on a tightrope! You could plummet with errors if you don't tread carefully. For example:

let adventurer = { backpack: null };

In the old-school way without optional chaining, you might verify each "hop" like this:

let ruby = (adventurer.backpack && adventurer.backpack.magicBox && adventurer.backpack.magicBox.ruby) || 'none';

But with the optional chaining operator, you can express the same idea much more concisely and readably:

// Adventurers knows the value of checking their backpacks for treasure before celebrations let ruby = adventurer?.backpack?.magicBox?.ruby || 'none';

Add in the nullish coalescing operator, and you've got a one-two punch for secure defaulting:

// Adventurers always have a default shiny stone just in case of no ruby let ruby = adventurer?.backpack?.magicBox?.ruby ?? 'shinyStone';

Dynamic properties: Safe checks, no exception wreck

When you're unaware of an object's full structure, trying to access non-existent properties may usher in exceptions. This situation can be handled by using optional chaining that defaults to undefined. Alternatively, when a null or undefined object crops up, step in with an empty object ({}) as a safeguard:

// No response from magicBox? Well, open the {emptyBox} instead. let ruby = ((adventurer?.backpack || {}).magicBox || {}).ruby;

Think of the above pattern as a kind of safe navigation mechanism in JavaScript, shielding your code against NullPointerExceptions.

Old environments? Transpile everything

One caveat about optional chaining and nullish coalescing: these are modern JavaScript features and might not be supported in older environments, even some that are still in common use. @babel plugins come to the rescue, transforming your new syntax to a digestible version for older browsers:

  • @babel/plugin-proposal-optional-chaining
  • @babel/plugin-proposal-nullish-coalescing-operator

By using these plugins, cutting-edge code can still run and shine in older platforms.