DEV Community

loading...
Cover image for How to Shorten JavaScript Conditionals with Short-Circuiting

How to Shorten JavaScript Conditionals with Short-Circuiting

reedbarger profile image Reed Barger Updated on ・5 min read

In this tip, you’ll learn how to reduce JavaScript conditionals to the smallest possible expression using a trick called short-circuiting.

What is short-circuiting?

As the name suggests, short-circuiting is a way we can shorten unnecessary checks in our conditionals by making use of some special tricks in the JavaScript language.

Let's see how:

We have a simple program where we ask users of it their name and if it’s a valid name, meaning not an empty string, we’ll set that equal to their username.

Otherwise, we’ll judge them to be anonymous and give them the username "guest". We’ll store that username as a variable.

How would we write this out as an if-else statement? Probably something like what we have here:

const response = "Reed"; // response from our user

let username;

if (response) {
  username = response;
} else {
  username = "guest";
}

console.log(username); // Reed
Enter fullscreen mode Exit fullscreen mode

But we can shorten this even more.

This if-else statement can be written more succinctly using the ternary operator, which is ideal for conditionally setting the value of a variable.

const response = 'Reed';
const name = response ? response : 'guest';
console.log(name); // Reed
Enter fullscreen mode Exit fullscreen mode

But we can even go a step further.

|| (or) short-circuiting

In this example, you might have noticed that we writing the information check, response, twice.

Let’s assume that data is always going to be valid, which means there’s no difference between the information we’re checking and the information we want. If it’s truthy, we’re going to use it.

Before updating the code, let's think about how logical operators, such as the or || operator, work.

The or operator, symbolized as ||, will return true if any of the possible values are true. We use it if the first value (called operand, in a conditional) or the second could evaluate to true.

Now here’s where it gets interesting--

Since in JavaScript we can use non-boolean values in our conditionals which are then coerced to true or false, if we use a truthy value in our || condition, it returns that truthy value and not the value true.

Let’s see this in action. If we have a valid name, which is a string and not a falsy value, it will be returned and put in username.

const username = "Reed" || "guest";
console.log(username); // 'Reed'
Enter fullscreen mode Exit fullscreen mode

Now you have all of the tools you need to rewrite the ternary to something even more concise.

const response = "Reed";
const username = response || 'guest';
console.log(username); // Reed
Enter fullscreen mode Exit fullscreen mode

As you may have noticed, the best part is that you can append a default value to the end of the expression. This means that you never have to worry about a variable being falsy because you know there’s a truthy value waiting at the end.

So there you have it. You can use short-circuiting to bypass information once something truthy occurs.

How about the other way around? How can you halt an expression once something false occurs? That’s possible as well.

Another popular usage of short-circuiting is to check multiple conditions.

&& short-circuiting

What if we are checking for a valid user, and on top of the user having a real name, they must have verified their email. If not, then they are once again a "guest".

How can we check to make sure that both conditions are true—a valid name and a verified email?

Let’s write this out in the long format with if statements and we’ll store whether the email is verified in a variable, isEmailVerified. Let’s say we have a name and the email is verified:

const response = "Reed";
const isEmailVerified = true;

let username;

let response = "";
let isEmailVerified = true;

if (response) {
  if (isEmailVerified) {
    username = response;
  } else {
    username = "guest";
  }
} else {
  username = "guest";
}

console.log(username);
Enter fullscreen mode Exit fullscreen mode

Again, this is a bit verbose. Fortunately, short-circuiting can help. Combining conditionals with the && operator will us to combine the two if conditionals into one.

How does the && operator work? The && operator will stop as soon as a false value occurs and will return the second value if true.

As our experience with the || operator tells us, the && operator can also accept truthy and falsy values.

For example:

const username = "guest" && "A better name";
console.log(username); // ‘A better name’
Enter fullscreen mode Exit fullscreen mode

But if we turn the first value on the left side to a falsy value (an empty string), the conditional stops at the first operand and returns the falsy value without going on to the second.

const username = "" && "A better name";
console.log(username); // ‘’
Enter fullscreen mode Exit fullscreen mode

So how does this help us? For the &&, if the first condition is true it moves onto the next, so instead of having multiple if statements, we can join them all with &&.

Let’s rewrite what we had:

const response = prompt("What’s your name?"); // I type in: Reed
const isEmailVerified = true;

let username;

if (response && isEmailVerified) {
  username = response;
} else {
  username = "guest";
}

console.log(username); // Reed
Enter fullscreen mode Exit fullscreen mode

This is significantly shorter, but by adding on the ternary operator, we can make it even shorter. Now that we know the && operator works, by returning the second operand, we need to put response second:

const response = "Reed";
const isEmailVerified = true;

const username = isEmailVerified && response || 'guest';
console.log(username); // Reed
Enter fullscreen mode Exit fullscreen mode

Operator precedence

Short-circuiting can be a very powerful technique, but be aware of operator precedence.

Operator precedence means the order in which operators are performed.

For example, do you know whether conditionals with && or || operators are executed first?

&& has higher precedence than ||, so it will always be executed first. You can either keep this in mind when writing your conditionals, or you can set which operators will be executed first using parentheses.

If you want to the || conditional to be executed first, you can wrap that part in parentheses, since parentheses have the highest precedence of all operators in JavaScript:

const username = isEmailVerified && (response || "guest");
Enter fullscreen mode Exit fullscreen mode

Use short-circuiting with caution

Be careful when combining ternaries and short-circuiting. Things can get out of hand very quickly. Though the code is terse, it may be hard for other programmers to understand.

There’s no explicit rule about how many conditionals are too many. It’s more a matter of taste and team agreement. When things get long (I would say around three conditional checks), it’s better to make it a standalone function.

Simplicity is great. It’s fun to try and find clever ways to reduce things to one line, but your goal always communication and readability.

Use short-circuiting to make things simpler and more readable—not to make your code needlessly succinct.

Enjoy this post? Join The React Bootcamp

The React Bootcamp takes everything you should know about learning React and bundles it into one comprehensive package, including videos, cheatsheets, plus special bonuses.

Gain the insider information hundreds of developers have already used to master React, find their dream jobs, and take control of their future:

The React Bootcamp
Click here to be notified when it opens

Discussion (17)

pic
Editor guide
Collapse
drcat7 profile image
Cat

Thank you for this post. You did well to put that final section warning against over-usage because it's easy to trick oneself into writing "smart" but ultimately barely-legible code.
Personally, the only short-circuit I feel makes sense is the x = y || z flavor. To me it naturally reads as "put y in x if can find it or put z if you can't".
By contrast, I feel an expression like w = x && y || z is not as easy to parse because the value you're really trying to put in w isn't next to =. x and y might not even be the same type like the post's example which makes readability even worse.

Collapse
zoedreams profile image
☮️✝️☪️🕉☸️✡️☯️

nice write up. thank you for sharing.

Here is a fun experiment with how creative you can get with logic operators and overloading. This function will take three inputs and return a different object type based on the result value. You can apply this design to many other situations when inject various contextual data types.

let x = Math.random() * 10 | 0 ^ Math.random() * 10 | 0 && Math.random() % 2 > 0,
  y,
  z;

if (!!!z && !!~x | 0 || z > -1) {
  y = x;
}

if (!!z && !!~x | 0 || z > -1) {
  y = x | 0;
}

console.log("y", y)
Collapse
oli8 profile image
Olivier

Why would you need three "!" ?

Collapse
zoedreams profile image
☮️✝️☪️🕉☸️✡️☯️ • Edited

the !! operand checks for if a value is set, or even is exists. The ! modifies this to return the XoR or opposite., These are handy when cloning objects or transforming objects based on their property of functional reflections. Try experimenting with those types of reserved primitive types.

let x = undefined || null || 1 || "" || ;
if (!!x) {
  console.log("exists");
}

jsfiddle.net/me19078q/

Thread Thread
oli8 profile image
Olivier

Yes but one "!" does the same thing as "!!!" and even the same thing as "!!!!!!!!!" to me.

Thread Thread
zoedreams profile image
☮️✝️☪️🕉☸️✡️☯️

sorry typo. Your correct. Adding more ! doesn't increase or affect the compiler, it just drops them off.

Collapse
lemraus profile image
Armel Chausse

Thanks for the post ! I just wanted to point out that your code sample for the "isEmailVerified" example has a small flaw: if the response is truthy and isEmailVerified is false, then the username variable will remain undefined instead of falling back to guest. The issue comes from the if statement imbrication.
Hope it makes sense, great work nonetheless !

Collapse
reedbarger profile image
Reed Barger Author

Thank you for catching that. Fixed it by adding a second else

Collapse
edii_martin profile image
Edival :)

Simplicity is great. It’s fun to try and find clever ways to reduce things to one line, but your goal always communication and readability.

This is a great advice. So many new js programmers don't get the importance of readability, they just want to use "js magic tricks" everywhere. Coding experience (specially with teams) gives you that feeling of what needs to keep simple and straightforward.

Thanks for the article!

Collapse
merri profile image
Vesa Piittinen

I often use this style when I need to output a string based on conditions that have priority and displaying only one of them matters.

const message =
    (isDangerous && 'Be careful') ||
    (isSilly && 'Prepare to laugh') ||
    (isTempting && 'Do NOT click!') ||
    (isQuestionable && 'Are you sure?') ||
    'Default message'

When building good old classNames in BEM style it does result in rather readable code:

const className = 'component' +
    (isActive ? ' component--is-active' : '') +
    (hasBorder ? ' component--has-border' : '') +
    (hasWalls ? ' component--has-walls' : '') +
    (hasLadders ? ' component--has-ladders' : '')

I've found myself to like this more than the use of classnames utility. The only gotcha is to remember to add the extra space before each modifier.

This same building style also works very well for CSS-in-JS style objects.

For the most part I think these solutions are very readable, easy to understand, and help avoid use of "unnecessary" extra libraries that people like to add into their projects.

Collapse
xai1983kbu profile image
xai1983kbu • Edited

Hi Reed!

I run this in Browser console:
123 && 456 && null && false && 789
null
It searches first falsy and returns it if falsy was not found then the last truthy value is returned.

I always forgot how it works. It seems now I have remembered it forever.
Thank you!

Collapse
carljf profile image
Carl • Edited

You can't reassign a const; see JS Fiddle link below. RE: && Short Circuit example:
jsfiddle.net/ajf9e4n3/

// Change to 'let' vs 'const'
const response = "Reed";
const isEmailVerified = true;

let username;

// Can't redeclare / assign constants.
let response = "";
let isEmailVerified = true;

Collapse
jonrandy profile image
Jon Randy • Edited

Good explanation of how to use it to shorten code, but missing the explanation of what short-circuiting actually is, and why it's called that (it's not because it can be used to shorten code)

Collapse
reedbarger profile image
Reed Barger Author

"As the name suggests, short-circuiting is a way we can shorten unnecessary checks in our conditionals by making use of some special tricks in the JavaScript language."

Collapse
airmind profile image
Alex Ágreda

I think what Jon meant, Reed, was the missing part of explaining those "special tricks".

That JS will not check the "second" part of a || expression because the first one being true is enough to return true, and a && expression will always need to check the "second" part because it need both to be true to return true

Thread Thread
jonrandy profile image
Jon Randy • Edited

Also explaining that expression evaluation will completely stop i.e. further function calls in the expression after the short circuit will not occur. This is not the same in all languages. Some do not have short circuit evaluation

Collapse
mistermoses profile image
Dan

const username = isEmailVerified && (response || "guest");

should be

const username = (isEmailVerified && response) || "guest";