🎩The Magic of || and && in JavaScript
Tags: javascript, computerscience
Published: 2022-07-16 20:34:18

In JavaScript, it's common to see code like this:

```js
const color = options.color || 'red';
```

Or like this:

```js
const name = data && data.name;
```

You might know what this code does, but maybe you don't know *why*. A couple of simple but very clever core language mechanics enable us to write code like this. Despite the clickbait title, there is (sadly) no magic involved. Let's take a look at what's really going on here.

In case you don't know what this code does: the former snippet provides a default value for the `color` variable. If `options.color` is a [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) value (such as a non-empty string), then `color` gets set to that value. But if `options.color` is a [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) value, such as undefined, then `color` gets set to the default value of `'red'`.

The latter snippet guards against `data` being undefined (or null). If `data` is undefined, then trying to reference `data.name` directly will result in an error being thrown. But if we use the `&&` trick, there will be no error in such a case. `name` will just be set to undefined.

## Boolean Expressions and Short-Circuit Evaluation

To understand how this works, it's important to first understand [short-circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation).

In a language like JavaScript, short-circuit evaluation means that when a JavaScript engine evaluates a boolean expression (such as `a || b`), it will only evaluate as much of the expression as it needs to, in order to find the answer.

In the expression `a || b` (meaning `a` OR `b`), think logically about what happens if `a` is `true`. If `a` is true, then it doesn't even matter what `b` is, right? `b` could be `true`, `false`, or anything else, and the result of `a || b` will be true regardless. If `a` is true, then `a` OR `b` is also true, period.

JavaScript engines are smart enough to know this too, and in practice it means that if `a` is `true` (or any other truthy value), the engine won't even bother looking at `b`.

To see this in action, you could try running the following code:

```js
console.log(true || null.abc);
```

While it's illegal to try to reference a property on `null`, this code does not error, because the engine never evaluates the right-hand-side of the expression! It doesn't need to, because the left-hand-side is sufficient to answer the question on its own.

## Boolean Operators Don't Return Boolean Values!

The second piece of the puzzle is what's returned by boolean operators, such as `||` and `&&`. Often, developers assume that these operators return boolean values, but that's actually not the case.

Try running this code:

```js
console.log('a' || 'b');
```

It does NOT return `true`. It returns `'a'`!

And this code:

```js
console.log('a' && 'b');
```

returns `'b'`!

What's going on here? This is the part that I find really clever. Boolean expressions do not return boolean values, they actually return *the last thing that was evaluated*.

Thanks to short-circuit evaluation, when evaluating the expression `'a' || 'b'`, the engine only evaluates the left-hand-side of the expression. That means that `'a'` is the last thing that it evaluates in this expression. Therefore, the return value of the expression is `'a'`.

In the expression `'a' && 'b'`, the left-hand-side of the expression is truthy, but because this is an `AND` operation, the engine still has to look at the right-hand-side to check if it's truthy or not. If it is, the expression is true. If it's not, then the expression is false. That means in this case, the final thing that's evaluated in this expression is `'b'`. That's why `'b'` is the return value of the expression.

## Putting it Together

That's the theory, but we can boil it down into simpler-sounding rules that might make it easier to use in practice:

1. The `||` operator returns the thing on left-hand-side, if that thing is truthy. If it's not, it returns the thing on the right-hand-side.
2. The `&&` operator returns the thing on the left-hand-side, if that thing is *falsy*. If it's not, it returns the thing on the right-hand-side.

Let's look at the examples from the top of the article again:

```js
const color = options.color || 'red';
```

Applying rule #1, if `options.color` is truthy, the expression returns `options.color`. Otherwise, it returns `'red'`.

```js
const name = data && data.name;
```

Applying rule #2, if `data` is falsy, the expression returns `data`. Otherwise, it returns `data.name`.

## Getting Fancy

You can get pretty fancy with this. For example, if you want to look at a property deep inside of an object, and provide a default value if it's not there, you could write code like this:

```js
const name = (data && data.profile && data.profile.name) || 'Name Unknown';
```

If `data` is truthy, it will return the thing on the right. The thing on the right is yet another boolean expression, where if `data.profile` is truthy, it too will return the thing on the right. If any of this is falsy, then `(data && data.profile && data.profile.name)` will return the last thing it evaluated. Since that thing would be falsy, `||` will return the thing on the right-hand-side, `'Name Unknown'`.

Does that sound a bit convoluted? I hope it does, and I wouldn't recommend writing code like this. It can get pretty hard to understand. But if you do understand it, then congratulations, you understand the magic of JavaScript boolean expressions.

### Optional Chaining and Nullish-Coalescing

As an aside, while code like the above used to be somewhat common in JavaScript, the new-ish optional chaining and nullish-coalescing features give us a simpler way to do the same thing:

```js
const name = data?.profile?.name ?? 'Name Unknown';
```

We won't dive into that, but it deserves mention.

## Conclusion

JavaScript engines only evaluate the parts of a boolean expression that they need to, and boolean expressions return the last thing that was evaluated. That's it. It's a simple mechanism, but it enables some pretty magical-looking constructs. Hopefully this article helped unwind the mystery, and if you have any questions or comments please post them below!