This if statement alternative only works in JavaScript

I’m not one of those who go on screaming about how horrible if statements are — in many cases, they are simply the best choice out of all the ways to create control flow.

Yet there are lots of situations where a different construct will do a noticeably better job of expressing our code’s intent — something we can’t ignore as long we write code for humans. Not to mention lower verbosity and shorter code.

So, let’s look at some powerful if statement alternatives.

1. The AND (&&) operator

This one is unique to JavaScript.

We quickly go from this:

JavaScript
function visitSite(user) { if (user.isLoggedIn) { console.log(`You are ${user.name}`); } console.log('Welcome to Coding Beauty.'); }

To this:

JavaScript
function visitSite(user) { user.isLoggedIn && console.log(`You are ${user.name}`); console.log('Welcome to Coding Beauty.'); }

We’ve eradicated the nested and compacted the branching logic into a one-liner.

You want to use this when there’s an if but no matching else; especially when the if block has only one line.

Even if there are multiple lines you can abstract them into a separate function and apply && again. After all the console.log() in our example is an abstraction itself.

So this:

JavaScript
function visitSite(user) { if (user.isLoggedIn) { console.log(`Welcome back, ${user.name}!`); console.log( `Your last login was on ${user.lastLoginDate}` ); console.log(`Your account type is ${user.accountType}`); } console.log('Welcome to Coding Beauty.'); }

Transforms to this:

JavaScript
function visitSite(user) { user.loggedIn && handleUser(user); console.log('Welcome to Coding Beauty.'); } function handleUser(user) { console.log(`Welcome back, ${user.name}!`); console.log( `Your last login was on ${user.lastLoginDate}` ); console.log(`Your account type is ${user.accountType}`); }

2. Ternary operator

Ternary operators let us compact if-else statements into a one-liner.

They’re great if-else replacements when all conditional cases only involve assigning a value to the same variable.

Here’s an example:

JavaScript
let word; if (num === 7) { word = 'seven'; } else { word = 'unknown'; }

Even though the DRY principle isn’t a hard and fast rule, for this instance things will be much cleaner if we used ternaries to avoid writing the variable assignment twice:

JavaScript
const word = num === 7 ? 'seven' : 'unknown';

Now we can even use const to keep things immutable and pure.

Nested ternaries

And when we have 3 or more branches in the if-else statement or we nest ifs, the cleaner ternary replacement will contain inner ternaries.

So this:

JavaScript
const getNumWord = (num) => { if (num === 1) { return 'one'; } else if (num === 2) { return 'two'; } else if (num === 3) { return 'three'; } else if (num === 4) { return 'four'; } else return 'unknown'; };

Becomes:

JavaScript
const getNumWord = (num) => num === 1 ? 'one' : num === 2 ? 'two' : num === 3 ? 'three' : num === 4 ? 'four' : 'unkwown';

Some people do cry about nested ternaries though, arguing that they’re complicated and cryptic. But I think that’s more of a personal preference, or maybe poor formatting.

And it’s formatting, we have tools like Prettier that have been doing this job (and only this job) for centuries.

Formatting nested ternary operators in VS Code with Prettier.
Ever had code this badly formatted?

As long as there’s sufficient indentation you should have no problems with readability. If the branching gets much more complex than above you probably want to move some of the lower-level logic into preceding variables or tiny functions.

Speaking of readability, Prettier is changing their nested ternary style; they’ve come up with something quite unique.

The current style uses a clever combination of flat and tree-like nesting; adding further indentation for nested ternaries in the truthy branch, but keeping things flat for those in the in the falsy branch.

JavaScript
const animalName = pet.canSqueak() ? 'mouse' : pet.canBark() ? pet.isScary() ? 'wolf' // Only nests this because it's in the truthy section : 'dog' : pet.canMeow() ? 'cat' : pet.canSqueak() // Flat because it's in the falsy section ? 'mouse' : 'probably a bunny';

But very soon Prettier will format the above like this:

JavaScript
const animalName = pet.canSqueak() ? 'mouse' : pet.canBark() ? pet.isScary() ? 'wolf' : 'dog' : pet.canMeow() ? 'cat' : pet.canSqueak() ? 'mouse' : 'probably a bunny';

The main change is the ?‘s are all now at the ending of the same line of its ending, instead of the next one.

3. Switch statement

You will find this in C-style languages like Java, C#, and Dart — and it looks exactly the same in those languages with a few semantic differences.

If ternaries are best for generating output for one variable, then switch statements are best for processing input *from* one variable:

JavaScript
function processUserAction(action) { switch (action) { case 'play': // if (action === 'play') console.log('Playing the game...'); startGame({ mode: 'multiplayer' }); break; case 'pause': // else if (action === 'pause') console.log('Pausing the game...'); pauseGame(); break; case 'stop': console.log('Stopping the game...'); endGame(); goToMainMenu(); break; case 'cheat': console.log('Activating cheat mode...'); enableCheatMode(); break; default: // else console.log('Invalid action!'); break; } }

The unique power of switch statements comes from being able to omit the break at the end of each case and let execution “fallthrough” to the next case:

JavaScript
// Generate a random number between 1 and 6 to simulate rolling a dice const diceRoll = Math.floor(Math.random() * 6) + 1; console.log(`You rolled a ${diceRoll}!`); switch (diceRoll) { case 1: console.log('Oops, you rolled a one!'); console.log('You lose a turn.'); break; case 2: console.log( 'Two heads are better than one... sometimes' ); case 4: case 6: // else if (diceRoll === 2 || diceRoll === 4 || diceRoll === 6) console.log('Nice roll!'); console.log('You move forward two spaces.'); break; // ... default: console.log('Invalid dice roll.'); }

Most other languages with switch-case allow this, with the notable exception of C#.

4. Key-value object

Key-value objects let us declaratively map inputs to outputs.

JavaScript
const weatherActivities = { sunny: 'go to the beach', rainy: 'watch a movie at home', cloudy: 'take a walk in the park', snowy: 'build a snowman', }; const weather = 'sunny'; console.log(`Okay, so right now it's ${weather}.`); console.log(`Why don't you ${weatherActivities[weather]}?`);

I found this invaluable when creating screens in React Native apps – each with its own loading, error and success states. Here’s a snippet of a screen in one of our apps:

JavaScript
// screens/course-list.tsx // ... import { ActivityIndicator, Text // ... } from 'react-native-paper'; type ViewState = 'loading' | 'error' | 'data'; export function Courses({ route, navigation }) { const [viewState, setViewState] = useState<ViewState>('loading'); const state = useAppState(); const courses = state?.courseList; // ... const contentDict = { loading: <ActivityIndicator />, error: <Text>Error</Text>, data: <CourseList courses={courses} />, }; const content = contentDict[viewState]; return ( <View> <StatusBar /> {content} </View> ); } // ...

Final thoughts

So if statements aren’t bad at all and are great for writing conditional logic in an easily understandable way. But it’s important to consider alternative approaches to make code shorter, clearer and even more expressive. It’s not about eliminating if statements entirely, but rather adopting effective techniques that make our code more efficient and elegant.



Every Crazy Thing JavaScript Does

A captivating guide to the subtle caveats and lesser-known parts of JavaScript.

Every Crazy Thing JavaScript Does

Sign up and receive a free copy immediately.

Leave a Comment

Your email address will not be published. Required fields are marked *