The Ultimate Guide to Default Values in JavaScript: || and ?? Operators Explained

Learn When to Use the Logical OR and Nullish Coalescing Operators.

One of the most common tasks in JavaScript is providing default values for variables that may be falsy or nullish.

Two operators that are commonly used for this are the logical OR (||) and the nullish coalescing (??) operators, but they definetely are not the same.

In this post, we'll explore the differences between these two operators and when to use each one.

The Logical OR (||) Operator

The logical OR (||) operator is used to provide a default value when a variable is falsy. The falsy values in JavaScript are false, 0, '' (empty string), null, undefined, and NaN.

When using the || operator, the first operand is returned if it evaluates to true; otherwise, the second operand is returned.

Here's an example:

const a = false || 'bar';  // returns 'bar'
const b = '' || 'qux';     // returns 'qux'
const c = null || 'corge'; // returns 'corge'

In this example, a is assigned the value 'bar' because false is falsy; b is assigned 'qux' because '' is falsy, and c is assigned 'corge' because null is falsy as well.

The || operator is useful when you want to provide a default value for falsy values, as well as nullish values.

However, it's important to note that the || operator can have unintended consequences when the operands are not of the same type, due to JavaScript's type coercion rules. For example:

const foo = '' || 0;  // returns 0

Here, the '' operand is coerced to the number 0, which is the last operand and is returned. To avoid these issues, it's generally safer to use the nullish coalescing operator (??) when checking for nullish values.

The Nullish Coalescing (??) Operator

The nullish coalescing (??) operator is used to provide a default value when a variable is nullish. The nullish values in JavaScript are null and undefined.

When using the ?? operator, the first operand is returned if it is not null or undefined; otherwise, the second operand is returned.

const a = null ?? 'bar';  // returns 'bar'
const b = '' ?? 'qux';    // returns ''
const c = undefined ?? 'corge'; // returns 'corge'

In this example, a is assigned the value 'bar' because null is nullish; b is assigned '' because '' is not nullish, and c is assigned 'corge' because undefined is nullish and the second operand is returned.

The ?? operator is useful when you want to provide a default value for nullish values only, without also including falsy values. This can help prevent unintended consequences when using different types of operands, as it only checks for nullish values.

Choosing between || and ??

If you want to provide a default value for falsy values in addition to nullish values, you should use the || operator. If you only want to provide a default value for null and undefined, you should use the ?? operator.

These operators have different use cases and can't always be used interchangeably. Let's contrast the previous examples:

const a = false || 'bar';  // returns 'bar'
const a = null ?? 'bar';  // returns 'bar'

const b = '' || 'qux';     // returns 'qux'
const b = '' ?? 'qux';    // returns ''

const c = null || 'corge'; // returns 'corge'
const c = undefined ?? 'corge'; // returns 'corge'

The result is the same for a and c, but look at the result for b; this happens because '' is a falsy value and 'qux' is returned when we use ||, but '' is not a nullish value, and then '' itself is returned when we use ??.

Real-World Examples

Here are some real-world examples of how the || and ?? operators can be used:

Example 1: Providing a default value for a function parameter

function printName(name) {
  console.log(`Hello, ${name || 'world'}!`);
}

printName(); // prints "Hello, world!"
printName(''); // prints "Hello, world!"
printName('Alice'); // prints "Hello, Alice!"

In this example, the printName function uses the || operator to provide a default value of 'world' if name is falsy. This allows the function to be called without any arguments or with an empty string and still print a default message.

If we had used the ?? operator, it would print "Hello, !" when passing an empty string. So, the || makes more sense here.

Example 2: Providing a default value for a configuration object

javascriptCopy codeconst config = {
  apiUrl: process.env.API_URL || 'https://example.com/api',
  apiKey: process.env.API_KEY ?? 'default-key',
};

In this example, the config object uses the || operator to provide a default value for apiUrl if process.env.API_URL is falsy. It uses the ?? operator to provide a default value for apiKey if process.env.API_KEY is nullish.

The || is also a better fit in this case, because an empty string would be swapped by a default value, which is important when dealing with environment variables.

Example 3: Using a default value for a missing property

const user = {
  name: 'Alice',
  age: 30,
};

console.log(user.name || 'Unknown'); // prints "Alice"
console.log(user.email || 'Unknown'); // prints "Unknown"

In this example, the user object uses the || operator to provide a default value of 'Unknown' for the missing email property. This allows the program to gracefully handle missing or incomplete data.

But... when to use the ?? operator, then? 🤔

So far in our examples, we demonstrated how the || would be a better option, since it takes care of empty strings and that was a wanted behavior in those cases.

You see, while the || operator can be useful for providing default values for string parameters, it can lead to unexpected results when used with numbers or booleans. Consider this code:

const value1 = 0 || 42; // returns 42
const value2 = false || true; // returns true

Here, the || operator returns the second operand (42 and true) instead of the falsy first operand (0 and false). This will most certainly lead to bugs if 0 and false are valid and expected values.

This is where the ?? operator shines, since it will only provide a default value if the value is null or undefined. Let's see:

const value1 = 0 ?? 42; // returns 0
const value2 = false ?? true; // returns false

In this example, the ?? operator returns the first operand (0 and false) because they are not nullish values.

Let's see a real world example:

function getValueOrDefault(num, defaultValue) {
  num = num ?? defaultValue;
  return num;
}

console.log(getValueOrDefault(42, 10)); // returns 42
console.log(getValueOrDefault(0, 10)); // returns 0
console.log(getValueOrDefault(null, 10)); // returns 10
console.log(getValueOrDefault(undefined, 10)); // returns 10

In this example, we only use the defaultValue if num is null or undefined. Pay special attention to the second example, where we pass 0 as num, which is a perfectly valid number, and it is used instead of the alternative 10.

So, in general, when working with numbers or booleans, it's usually better to use the ?? operator to avoid unexpected behavior and ensure that valid input values are not treated as falsy.

Conclusion

When choosing between the || and ?? operators, it'simportant to consider the behavior of each operator and choose the one that best fits your use case.

In summary, here are some guidelines to keep in mind when using these operators:

  • Use the || operator if you want to provide a default value for falsy values in addition to nullish values.

  • Use the ?? operator if you only want to provide a default value for null and undefined.

  • Avoid using the || operator with operands of different types, as it can lead to unintended consequences due to JavaScript's type coercion rules.

  • The || is usually better for strings, while the ?? is usually better for numbers and booleans.

  • When in doubt, use the ?? operator, as it is safer and more predictable when checking for nullish values.

Happy coding!