We use cookies to improve your experience.

Using Nullish Coalescing (??) and Logical OR (||) correctly in JavaScript

AG Software Development

4 minutes

Using Nullish Coalescing (??) and Logical OR (||) correctly in JavaScript

When building applications and website using JavaScript, you may have seen or used both operators, in cases where a default value is to be used, or when we need a value to fall back on.

You may have seen both operators being used in cases where a default value is to be used, or when we need a value to fall back on. Although they might seem similar, at first glance, there are a couple of subtle, yet key, differences as to how they behave.

A quick look into both

Logical OR (II)

The logical OR operator (||) is typically used with Boolean values and returns the first truthy value it encounters. Take, for instance, the following example:

const numberToUse = 1 || 0; // 1

In this case, the OR operator encounters 1, which is by default a truthy value and therefore, numberToUse is assigned the value of 1.

While this example is straightforward, there is an important catch - using this operator with non-Boolean values, will result in it returning a non-Boolean value.

const messageToShow = 'hello' || 'hi'; // hello

In this case, given how both strings are truthy values, messageToShow will be assigned the value of hello.

In more realistic examples, where we need to check, for instance, for a field's previously provided value, it is important to keep in mind that this operator assigns the first truthy value it encounters.

Nullish Coalescing (??)

The nullish coalescing operator in the other hand, does not take into account all falsy values, as it checks whether the value on the left is null or undefined, and if it is, it returns the value on the right.

In essence, the nullish coalescing operator is used to explicitly check whether the value is null or undefined.

const value1 = null;
const value2 = false;
const defaultValue = 'default'

const result1 = value1 ?? defaultValue; // 'default'
const result2 = value2 ?? defaultValue; // false

In this example, we can see that when we used the nullish coalescing operator (??) to assign a value to the constant result1, since the first operand was null, the second operand was assigned. Respectively, for result2, since the first operand was neither null nor undefined, it ended up with the value of false

So, what difference does it make?

In essence, there are a lot of scenarios where either operator would work just fine, without any noticeable side effects. However, we must keep in mind that, for cases where we are intending to receive falsy values, including null & undefined, and handle them differently, we must use the nullish coalescing operator.

Take, for instance, the following scenario - we have a simple function which takes in an object and returns a new configuration object, with fallback values for each property.

Using the coalescing operator here means that any passed value to the properties will be accepted, unless it is null or undefined, in which case the fallback will be triggered.

const getConfiguration = (userConfiguration) => {
  const defaultConfig = {
    theme: 'light',
    showNotifications: true,
    retryAttempts: 10,
  };

  return {
    theme: userConfiguration.theme ?? defaultConfig.theme,
    showNotifications: userConfiguration.showNotifications ?? defaultConfig.showNotifications,
    retryAttempts: userConfiguration.retryAttempts ?? defaultConfig.retryAttempts,
  };
};

const userOneConfiguration = {
  theme: 'system',
  showNotifications: false,
  retryAttempts: 0,
};

const userTwoConfiguration = {
  theme: 'light',
};

const configOne = getConfiguration(userOneConfiguration);
// { theme: "system", showNotifications: false, retryAttempts: 0 }
const configTwo = getConfiguration(userTwoConfiguration); 
// { theme: "light", showNotifications: true, retryAttempts: 10 }

However, if we were to substitute the nullish coalescing operator with a logical OR and we intended on keeping the showNotifications and retryAttempts values for userOneConfiguration, we could be introducing a bug.

const getConfiguration = (userConfiguration) => {
  const defaultConfig = {
    theme: 'light',
    showNotifications: true,
    retryAttempts: 10,
  };

  return {
    theme: userConfiguration.theme || defaultConfig.theme,
    showNotifications: userConfiguration.showNotifications || defaultConfig.showNotifications,
    retryAttempts: userConfiguration.retryAttempts || defaultConfig.retryAttempts,
  };
};

const userOneConfiguration = {
  theme: 'system',
  showNotifications: false,
  retryAttempts: 0,
};

const configOne = getConfiguration(userOneConfiguration);
// expected: { theme: "system", showNotifications: false, retryAttempts: 0 }
// actual: { theme: "system", showNotifications: true, retryAttempts: 10 }

As you can see, while we are explicitly passing values for showNotifications and retryAttempts, the fallback values are triggered and the configuration object we receive does not correspond to what we intended.

To sum up

In summary, while both the logical OR (||) and nullish coalescing (??) operators are useful for providing default values in JavaScript, they serve different purposes and behave differently. The logical OR operator will return the first truthy value it encounters, which can inadvertently override intended falsy values such as 0, false, or an empty string. In contrast, the nullish coalescing operator is specifically designed to handle null or undefined values, making it a better choice when you need to preserve falsy values that are not null or undefined.

Understanding these differences is crucial for avoiding subtle bugs in your code and ensuring that your application handles default values correctly. Thank you for taking the time to read this article. Happy coding!