Null Coalescing Operator in JavaScript with ECMAScript 2020

Introduction

When working in a request-response lifecycle, you want to make sure that a response with the wanted body - or at least an informative response arrives so the client that requested the data stays in the loop. In case of null values, you'll probably want to return a different result.

JavaScript made sure this can be handled with its nullish operator also known as the Null Coalescing Operator, which was added to the language with ECMAScript 2020. With it, you can either return a value or assign it to some other value, depending on a boolean expression.

This can be used to return default values if another value is missing, or to return different values based on any other boolean expression.

The Null Coalescing Operator belongs to the group of short-circuiting logical operators, which we'll take a look at in a moment.

It's somewhat similar to the Conditional Operator, which is sometimes known as the Ternary Operator:

// Null Coalescing Operator
// If the left-hand side is null, the right-hand side is returned
result = nullValue ?? defaultValue

// Conditional Operator
// If the condition is true, the left side is assigned, otherwise, the right side is assigned
condition ? value : value2

In this guide, we'll be taking a look at the nullish/Null Coalescing Operator, short-circuiting and truthy and falsy values - through practical examples.

What is short-circuiting?

JavaScript evaluates operators from left to right. With exclusive operators where we need both values to evaluate to true, it's sometimes enough to check just the first evaluation statement.

If the left side of the operator is false, regardless of the right side, the operator results in false, so there's no point in evaluating the other side, and it's skipped to preserve computational power.

This process is called short-circuiting.

Before ES2020, JavaScript only had two short-circuit logical operators:

  • Logical operator AND - &&
  • Logical operator OR - ||

With the new update, JavaScript introduced another one:

  • Null Coalescing operator - ??

Short-circuiting itself makes code more efficient because less evaluations need to happen, though, via the Null Coalescing operator, we can also alter the code logic based on a short-circuiting operation.

For instance:

let x = 10;
let y = 20;

let result;

if (x+y > 20){
    result = "x+y is greater than 20";
}

console.log(result);

This code will result in:

x+y is greater than 20

Though, we could also ditch the if statement fully and use a short-circuit AND operator instead to shorten the statements:

let x = 10;
let y = 20;

(x+y) > 20 && console.log("x+y is greater than 20");

(x+y) > 20 evaluates to true so the next block is entered, and the message is printed.

Where is short-circuiting here?

If the (x+y) > 20 was falsy (we'll talk about this in a second), the JavaScript interpreter wouldn't even look at the second part of the expression, and the block would never run.

Similarly enough, we can use the logical OR operator in a similar way:

let x = 10;
let y = 20;

(x-y) > 0 || console.log("x+y is lesser than 0");
Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

Naturally, this results in:

x+y is lesser than 0

These examples are pretty simple, yet logical operators can solve a lot of practical problems and make your code a lot cleaner. However, if not used properly, you might cause yourself a headache.

Truthy and Falsy values

When working with logical operators, you'll come around the terms truthy value and falsy value.

A truthy value is any value that isn't:

  • null
  • undefined
  • 0
  • '' - empty string
  • false
  • NaN - Not a Number

All these values are considered falsy.

In JavaScript, all the falsy values are evaluated as false when used in loops or if statements and all the truthy values are evaluated as true.

Now that we've got the prerequisites covered, let's finally take a look at the Nullish Operator.

Nullish Coalescing Operator

The Nullish Operator checks whether the value is nullish, not falsy. A nullish value is undefined or null.

This allows us to assign default non-null values to variables when we're unsure of the results.

For instance, let's mock a user service that retrieves a user from a database and returns their name. There's a 10% chance that the user doesn't exist, which is regulated by a Math.random() call. In 10 calls to the database, we're likely to see at least one missing user - denoted by a null result:

class DbConnection {
  find(id) {
    if (Math.random() > 0.9) {
      return null;
    } else {
      return `John Doe ${id}`;
    }
  }
}

const db = new DbConnection();

for (let i = 0; i < 10; i++) {
  let user = db.find(i);

  if (user != null){
    console.log(user);
  } else {
    console.log('User not found');
  }
}

The code will output either the name or a message denoting the lack of the user's existence in the database, though this requires us to perform null-checks in the if statement.

This results in:

John Doe 0
John Doe 1
User not found
John Doe 3
John Doe 4
John Doe 5
User not found
User not found
John Doe 8
John Doe 9

By happenstance, this seems to be an odd run - 3 null results! This code works just fine, and handles null cases if the database returns a null value.

Alternatively, we could've used something much more concise:

class DbConnection {
  find(id) {
    return Math.random() > 0.9 ? null : `John Doe ${id}`
  }
}

const db = new DbConnection();

for (let i = 0; i < 10; i++) {
  let user = db.find(i) ?? "User not found"
  console.log(user)
}

Using a conditional operator, we've returned either null or John Doe with their respective ID. If Math.random() > 0.9, null is returned, so there's a 10% probability it'll be returned on each call to the database.

Then, assuming possible null values - we've used the Nullish Operator to assign a new value to the user result if it turns out to be null. If db.find() returns null, the right-hand value kicks in and is returned instead.

This code is much cleaner and shorter than the if-else statements, and if-else statements have a higher tendency to cascade and get even more complex. Though, chaining multiple short-circuiting operators gets hard to read as well, so it's not really advisable to replace all if-else blocks:

let s1 = (Math.random() > 0.5 ? 1 : null) ?? (Math.random() > 0.5 ? 4 : (Math.random() > 0.5 ? null : 1))

console.log(s1)

Do you know what this would print? Considering random possibilities, it'd likely take you a while to parse this manually and see which values you can anticipate. This code has a tendency to result in 1 with null and 4 in some cases, as the returned default value for the nullish operator in this case is another null. Typically, you won't use more than one, or two, operators in cases like these.

Conclusion

To wrap this up, the sole purpose of the nullish operator is to allow you to always return some kind of default value, instead of returning something that doesn't exist - which, in JavaScript, is what null and undefined mean.

Last Updated: March 22nd, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms