How to shorten my conditional statements

I have a very long conditional statement like the following:

if(test.type == 'itema' || test.type == 'itemb' || test.type == 'itemc' || test.type == 'itemd'){
    // do something.
}

I was wondering if I could refactor this expression/statement into a more concise form.

Any idea on how to achieve this?


Put your values into an array, and check if your item is in the array:

if ([1, 2, 3, 4].includes(test.type)) {
    // Do something
}

If a browser you support doesn't have the Array#includes method, you can use this polyfill.


Short explanation of the ~ tilde shortcut:

Update: Since we now have the includes method, there's no point in using the ~ hack anymore. Just keeping this here for people that are interested in knowing how it works and/or have encountered it in other's code.

Instead of checking if the result of indexOf is >= 0, there is a nice little shortcut:

if ( ~[1, 2, 3, 4].indexOf(test.type) ) {
    // Do something
}

Here is the fiddle: http://jsfiddle.net/HYJvK/

How does this work? If an item is found in the array, indexOf returns its index. If the item was not found, it'll return -1. Without getting into too much detail, the ~ is a bitwise NOT operator, which will return 0 only for -1.

I like using the ~ shortcut, since it's more succinct than doing a comparison on the return value. I wish JavaScript would have an in_array function that returns a Boolean directly (similar to PHP), but that's just wishful thinking (Update: it now does. It's called includes. See above). Note that jQuery's inArray, while sharing PHP's method signature, actually mimics the native indexOf functionality (which is useful in different cases, if the index is what you're truly after).

Important note: Using the tilde shortcut seems to be swathed in controversy, as some vehemently believe that the code is not clear enough and should be avoided at all costs (see the comments on this answer). If you share their sentiment, you should stick to the .indexOf(...) >= 0 solution.


A little longer explanation:

Integers in JavaScript are signed, which means that the left-most bit is reserved as the sign bit; a flag to indicate whether the number is positive or negative, with a 1 being negative.

Here are some sample positive numbers in 32-bit binary format:

1 :    00000000000000000000000000000001
2 :    00000000000000000000000000000010
3 :    00000000000000000000000000000011
15:    00000000000000000000000000001111

Now here are those same numbers, but negative:

-1 :   11111111111111111111111111111111
-2 :   11111111111111111111111111111110
-3 :   11111111111111111111111111111101
-15:   11111111111111111111111111110001

Why such weird combinations for the negative numbers? Simple. A negative number is simply the inverse of the positive number + 1; adding the negative number to the positive number should always yield 0.

To understand this, let's do some simple binary arithmetic.

Here is how we would add -1 to +1:

   00000000000000000000000000000001      +1
+  11111111111111111111111111111111      -1
-------------------------------------------
=  00000000000000000000000000000000       0

And here is how we would add -15 to +15:

   00000000000000000000000000001111      +15
+  11111111111111111111111111110001      -15
--------------------------------------------
=  00000000000000000000000000000000        0

How do we get those results? By doing regular addition, the way we were taught in school: you start at the right-most column, and you add up all the rows. If the sum is greater than the greatest single-digit number (which in decimal is 9, but in binary is 1) we carry the remainder over to the next column.

Now, as you'll notice, when adding a negative number to its positive number, the right-most column that is not all 0s will always have two 1s, which when added together will result in 2. The binary representation of two being 10, we carry the 1 to the next column, and put a 0 for the result in the first column. All other columns to the left have only one row with a 1, so the 1 carried over from the previous column will again add up to 2, which will then carry over... This process repeats itself till we get to the left-most column, where the 1 to be carried over has nowhere to go, so it overflows and gets lost, and we're left with 0s all across.

This system is called 2's Complement. You can read more about this here:

2's Complement Representation for Signed Integers.


Now that the crash course in 2's complement is over, you'll notice that -1 is the only number whose binary representation is 1's all across.

Using the ~ bitwise NOT operator, all the bits in a given number are inverted. The only way to get 0 back from inverting all the bits is if we started out with 1's all across.

So, all this was a long-winded way of saying that ~n will only return 0 if n is -1.


You can use switch statement with fall thru:

switch (test.type) {

  case "itema":
  case "itemb":
  case "itemc":
  case "itemd":
    // do something
}

Using Science: you should do what idfah said and this for fastest speed while keep code short:

THIS IS FASTER THAN ~ Method

var x = test.type;
if (x == 'itema' ||
    x == 'itemb' ||
    x == 'itemc' ||
    x == 'itemd') {
    //do something
}

http://jsperf.com/if-statements-test-techsin enter image description here (Top set: Chrome, bottom set: Firefox)

Conclusion :

If possibilities are few and you know that certain ones are more likely to occur than you get maximum performance out if || ,switch fall through , and if(obj[keyval]).

If possibilities are many, and anyone of them could be the most occurring one, in other words, you can't know that which one is most likely to occur than you get most performance out of object lookup if(obj[keyval]) and regex if that fits.

http://jsperf.com/if-statements-test-techsin/12

i'll update if something new comes up.


If you are comparing to strings and there is a pattern, consider using regular expressions.

Otherwise, I suspect attempting to shorten it will just obfuscate your code. Consider simply wrapping the lines to make it pretty.

if (test.type == 'itema' ||
    test.type == 'itemb' ||
    test.type == 'itemc' ||
    test.type == 'itemd') {
    do something.
}