A short tale about switches and the alternatives in JavaScript

Do you like ‘if’ statements? Me neither… They’re cool and all but after writing the 3rd ‘if else’ you should probably stop for a moment and ask yourself, “What am I doing with my life?” If only there was a better way to run a specific piece of code based on some variable… Okay, enough fooling around, let’s get to the topic.

A short tale about switches and the alternatives in JavaScript
Contributor Photo - Dawid Rogowicz

Dawid Rogowicz

Frontend Developer

Chapter One - The Switch Situation

I won’t get into details about the syntax but here is a short reminder of what switches look like:

switch(userInput) {

  case 'LEFT':

    x -= 1;

    break;

  case 'RIGHT':

    x += 1;

    break;

  case 'UP':

    y += 1;

    break;

  default:

    y -= 1;

}

As you can see, it looks pretty clean and readable. Each engine handles optimization a little bit differently but the most important thing here is that if your target case is at the very end of a switch, you don’t have to wait for each of the preceding ones to get validated, the code jumps straight to where it should go.

What that means is the amount of cases doesn’t make a big difference when it comes to performance. We also get the possibility of running the same code for multiple cases without sacrificing the code’s readability.

Chapter Two - The Forgotten Solution

So, we know what switches are and their pros and cons, but that’s not the only way to achieve our goal. Let’s do a short summary of what other options we have.

If elses

This is what we’re trying to avoid. The code is messy and execution a bit slow. If your target ‘if’ is preceded by 10 different cases, you have to wait for each one of them to be validated. While it might be a go-to solution for most situations, with each additional statement it gets slower and less readable. We can get rid of the ‘else’ statements and place something inside of each ‘if’ to finish execution immediately after we find the target case.

if(userInput === 'LEFT') x -= 1;

else if(userInput === 'RIGHT') x += 1;

else if(userInput === 'UP') y += 1;

else y -= 1;

Objects

Yeah, you heard it right, objects! Even though they’re not meant for this, we can “hack” them to fit our needs. We pretty much can’t go wrong with switches, they fit perfectly the imperative paradigm of programming but if you’re one of those maniacs (like me) and you shed a tear with each new declared variable, you’d probably want to modify it somehow. Here’s how we could utilize objects in a nice “functional programming”-friendly way.

(({

  LEFT: () => (x -= 1),

  RIGHT: () => (x += 1),

  UP: () => (y += 1)

})\[userInput] || (() => (y -= 1)))();

We’re basically assigning functions to specific keys to run them, if the key isn’t found in the object, we can also declare a default function for such case.

Arrays

We’ve had objects so why not try arrays? We can access different content by index so it’s almost like objects with numbers as keys.

(([

  () => (x -= 1),

  () => (x += 1),

  () => (y += 1)

])\[userInput] || (() => (y -= 1)))();

Chapter Three - optimization

I hope you like math, numbers and colorful graphs because I’ve got something special for you. I prepared some benchmarks of different approaches we’ve covered. You can check it yourself here and run it on your computer to see what’s fastest for you.

What each of the tests is doing is assigning a value to ‘y’ based on const ‘x’ where ‘x’ is always in the last if/case/property, etc. to test the worst case scenario.

You might be also interested in the article:

Javascript's For Loop Statements - a brief guide

Javascript's For Loop Statements - a brief guide

Array

As you can see (or not), running functions straight from an array isn’t the fastest solution. In fact, it was so slow that you can’t even see it on the graph. It’s probably the worst idea; you’re limited to using numbers and, what’s more important, elements can change order. The performance speaks for itself - big no-no!

However, things change when we use primitive data types in the array (the top red bar).

Surprisingly, it got the best performance in Chrome and was at least noticeable in Firefox, so is it the way to go? I’d still advise against it due to the reasons mentioned before. Arrays just aren’t meant for such things. But hey, that’s what defines hacking.

Ifs

Both the ‘if’ (dark green) and ‘if’/‘else’ (orange) statements turned out pretty good. However, they should be the point of reference so let’s not let them rest on their laurels just yet. What’s worth noticing here is that ‘elses’ aren’t really slower. Of course it will depend on the engine used and the particular implementation but that’s the case in my example. I’ve already hated enough on using multiple ‘if’ statements one after another, so I think we can actually end it right here and move on.

Switches

Now to the fun part. I prepared three tests for switch statements. In two of them, cases are checked based on: number (purple) and string (light green) (See the picture above) .

Using numbers is quicker both in the SpiderMonkey (Firefox) and V8 (Chromium) engines. Is it worth it though? Taking into consideration that you’ll have to map integers to some meaningful value anyways, I don’t think so. Using strings is self-descriptive which is a great advantage and makes it easier to maintain code by other developers.

In the pink one, I assigned switch to function and returned our value. The output of this function would be later assigned to ‘y’. What I wanted to test here is to see whether returning from switch would be faster than just breaking. As it turns out, not really.

The last benchmark (dark red) is a switch that returns a value in each case (similar to what we did with arrays). Because we’re using ‘return’, there is no need to ‘break’ out of each case. It turns out that we’re better off doing our computation inside of each case instead of trying to narrow down the cases to contain only variables that are not common between those cases.

Epilogue - Something Ends, Something Begins

After seeing all of these fancy colors and numbers, I think it’s time to bring it all together and try to sum it all up. When it comes to performance, the best options are to use either ‘if’s or switches. Accessing datatypes like objects or arrays is just too slow and the difference is so big, I think we can reject both arrays and objects straightaway. I know arrays with primitives were actually the fastest solution in Chrome but there are some serious downsides to using them which I’ve already covered.

It all comes down to switches and ‘if’s then. Well… to switches actually! If you have two or three cases there is no need to use switches but I think that anything above that should be handled by a switch. It’s just what they’re meant for and using them will be a lot more readable.

Speaking of readability, I’ve already mentioned that it’s better to check cases by strings even though numbers would be slightly faster. In fact, the difference is so small nobody will notice it, so we’re better off focusing on making the code clean and easy to maintain.

The lesson learned here is that we can’t really beat the years of research and experience of Firefox/Chromium contributors in one evening!

Thanks for reading!

Contact:

Let's talk about
your business