Refactoring cascading conditionals in favor of readability
Tags: javascript, webdev
Published: 2021-06-23 17:14:40

**Written by [Juan Cruz Martinez](https://blog.logrocket.com/author/juancruzmartinez/)** ✏️

JavaScript is an extremely flexible programming language used to build pretty much anything you can think of, from websites, web applications, and desktop applications, to UIs for smart devices, server-side applications, and more.

JavaScript’s flexibility is what has allowed for its broad feature set — but, as we know, it is also responsible for [some strange behaviors](https://livecodestream.dev/post/stranger-things-javascript-edition/) that have ignited developers' imaginations. Some of the code we’ve written is uniquely suited to solving these strange problems in smart and elegant ways; some isn’t.

In this article, we’ll focus on analyzing the different ways developers have replaced wordy and confusing conditional statements — in particular, cascading `if/else if` and `switch` statements. Why? Because in JS, we can do better than just using `if`.

## Ternary, `&&`, and `||` operators

Let’s introduce a simple function with a conditional statement using `if`, and let’s refactor it using the [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator).

```javascript
if (condition) {
   return functionTrue();
} else {
   return functionFalse();
}
```

There’s nothing wrong with our example above, but we do unnecessarily take up a few lines of code repeating the keyword `return`. The ternary operator allows for simplification:

```javascript
return condition ? functionTrue() : functionFalse();
```

Isn’t that much simpler? But how does it work?

The ternary operator is the only JavaScript operator that takes three operands: a condition followed by a question mark (`?`), an expression for a truthy conditional followed by a colon (`:`), and finally an expression for a falsy conditional. Here is what it looks like:

```javascript
condition ? expressionIfTrue : expressionIfFalse
```

Note that both `true` and `false` expressions must be provided for the ternary operator to work. But what if we only need to do something when the condition is truthy?

JavaScript offers alternative methods of simplifying expressions by making use of the operators `&&` and `||`.

Let’s look at a different example where we only need to execute a statement when the condition is satisfied.

```javascript
if (condition) {
   console.log("it's true!");
}
```

We could rewrite this statement into a one-liner by using `&&`, like so:

```javascript
condition && console.log("it's true!");
```

The key reason this works is that JavaScript reads the operands in conditional statements from left to right and exits the moment it can invalidate the arguments. So, in the case of `&&`, if the first statement is falsy, there’s no point in evaluating the next, as the whole expression is falsy.

Similarly, the `||` operator will continue evaluating the operands until one of them is `true`, or the whole expression evaluates to `false`. Take a look at the below example:

```javascript
trueCondition || console.log("Hello world!"); // does not execute the console.log
falseCondition || console.log("Hello world!"); // executes the console.log
```

## Evaluating multiple results for an expression

Often, when we’re reading or writing code, we find multiple nested `if` conditions — such as in the following function, which takes the name of a fruit and returns its color.

```javascript
function getColor(fruit) {
   if (fruit.toLowerCase() === 'apple') {
       return 'red';
   } else if (fruit.toLowerCase() === 'banana') {
       return 'yellow';
   } if (fruit.toLowerCase() === 'orange') {
       return 'orange';
   } if (fruit.toLowerCase() === 'blueberry') {
       return 'blue';
   } if (fruit.toLowerCase() === 'lime') {
       return 'green';
   }

   return 'unknown';
}
```

Even when the code performs its function as expected, there are several things we could do better. For starters, the method `toLowerCase` is being called multiple times for each fruit, which could not only affect performance but also make the whole function less readable.

The next optimization would be to avoid repeating the conditionals, which reduces the number of instances we could introduce errors, such as forgetting to include the `toLowerCase` method in one of our lines.

We can quickly fix this by calling the method only once at the beginning of the function and evaluating each result — but we can do even better by using a [`switch`](https://www.w3schools.com/js/js_switch.asp) statement.

```javascript
function getColor(fruit) {
   switch(fruit.toLowerCase()) {
       case 'apple':
           return 'red';
       case 'banana':
           return 'yellow';
       case 'orange':
           return 'orange';
       case 'blueberry':
           return 'blue';
       case 'lime':
           return 'green';
       default:
           return 'unknown';
   }
}
```

This is looking much better, but it still doesn’t feel right. There are a lot of repeated keywords, which make it confusing to read.

Below is a different approach — a smarter, more elegant approach like we discussed at the beginning of this article.

```javascript
function getColor(fruit) {
   const fruits = {
       'apple': 'red',
       'banana': 'yellow',
       'orange': 'orange',
       'blueberry': 'blue',
       'lime': 'green',
   };

   return fruits[fruit.toLowerCase()] || 'unknown';
}
```

Simply beautiful. It’s easy to identify which fruit corresponds with each color, we aren’t repeating keywords, and it’s clearly read and understood.

This method for solving cascading `if` statements is called Jump Table. It can work for much more than simple texts or constants; let’s see a more complex example.

## Building Map objects

The Jump Table approach is great for simple texts and constants, but how would it work in more complex situations, like when `if` statements have multiple lines of codes with function calls?

Now that we understand how to simplify statements, the approach for these more complex scenarios is straightforward — it’s all about how we build our Map object.

Let’s build a `calculate` function with two numbers and an operation as an argument, and return the operation’s result over the two numbers.

```javascript
function calculate(number1, number2, operation) {
   const operations = {
       '+': (a, b) => a + b,
       '-': (a, b) => a - b,
       '*': (a, b) => a * b,
       '/': (a, b) => a / b,
   }

   return operations[operation]?.(number1, number2) ?? 'invalid operation';
}
```

As expected, the code looks very clean and a function is clearly assigned to each operation to perform the necessary calculations to get our desired result.

What looks a bit different, and perhaps strange, is the `return` statement; but the idea behind it is simple, so let’s break it down.

```javascript
operations[operation]?.(number1, number2)
```

The first part of the expression will simply return the given operation from the dictionary and execute the function if the key is present. If the key does not exist, it will return `undefined`. This last part is thanks to the [optional chaining operator](https://blog.logrocket.com/optional-chaining-and-nullish-coalescing-in-javascript/).

The second part uses the [nullish coalescing operator](https://blog.logrocket.com/6-cutting-edge-javascript-features-you-can-use-today/), which returns its right-hand side operand when its left-hand side operand is `null` or `undefined` and otherwise returns its left-hand side operand.

```javascript
?? 'invalid operation';
```

So, in our case, it will return the result of the operation when the operation is present in the dictionary, or it will return an `invalid operation`.

## Conclusion

[JavaScript is a flexible language](https://blog.logrocket.com/a-comprehensive-guide-to-javascript-expressions/) that offers multiple ways to solve a problem. In this article, we learned various alternatives to traditional `if` statements that can help you write clearer, better code.

It’s important to have multiple options in your code arsenal because there is no single solution that will be right for every situation. Additionally, JavaScript is evolving, and new ways will be introduced or discovered as new versions roll out, so it’s helpful to stay connected and read the latest articles to stay up to date.

Thanks for reading!

---

## [LogRocket] (https://logrocket.com/signup/): Debug JavaScript errors easier by understanding the context
Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.

[LogRocket] (https://logrocket.com/signup/) allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

[![LogRocket Dashboard Free Trial Banner](https://blog.logrocket.com/wp-content/uploads/2020/06/reproduce-javascript-errors.gif)](https://logrocket.com/signup/)

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

[Try it for free] (https://logrocket.com/signup/).