155

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?

ST3
  • 8,826
  • 3
  • 68
  • 92
FlyingCat
  • 14,036
  • 36
  • 119
  • 198
  • 23
    You can put them in an array and use `in`? – jeremy Aug 21 '13 at 00:32
  • 2
    http://snook.ca/archives/javascript/testing_for_a_v – Muhammad Umer Aug 21 '13 at 01:09
  • now only if someone could check which one is the fastest – Muhammad Umer Aug 21 '13 at 15:33
  • 3
    this maybe a shock to everyone but what OP has is a clear winner in speed!!!!!!! Maybe cause browser optimize for this a lot.. Results: (1) if with `||`. (2) `switch` statements. (3) regex. (4) `~`. http://jsperf.com/if-statements-test-techsin – Muhammad Umer Aug 21 '13 at 15:52
  • 4
    You may also be approaching this the wrong way. In this case, those 4 types have something in common. What is it? If we take this to a more extreme case, what if we needed to add 10 more types to match this condition. Or 100? If there were more, you probably wouldn't consider using this solution, or any of the others suggested. You're seeing a big if statement like this, and thinking it's a code smell, which is a good sign. Your best way to make this more concise would be if you could write if (test.your_common_condition). It's easier to understand in this context, and more extensible. – gmacdougall Aug 21 '13 at 16:35
  • Read: [Optimize OR in IF](http://stackoverflow.com/questions/15066671/optimize-or-in-if/15066953#15066953) – Grijesh Chauhan Aug 22 '13 at 11:04
  • In python this'd simply be `if test.type in ('itema', 'itemb', ...):` – Tobias Kienzler Aug 23 '13 at 12:03
  • @MuhammadUmer Those results are very weird when comparing the results between Firefox & Chrome, that difference is HUGE. – Dan Aug 28 '13 at 07:01
  • ff has beaten chrome in js speed recently so yea. – Muhammad Umer Aug 28 '13 at 17:22
  • This question is currently a duplicate of a duplicate of a duplicate of a duplicate of a duplicate. (this -> Javascript formatting for if condition -> Javascript: Comparing SINGLE Value Against MULTIPLE Values with OR Operands -> Javascript if statement with multiple permissible conditions ->Javascript If statement used to check file extensions not working) – travisbartley Sep 09 '13 at 06:08

15 Answers15

242

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.

Joseph Silber
  • 214,931
  • 59
  • 362
  • 292
  • this doesn't do the same thing tho – Muhammad Umer Aug 21 '13 at 00:34
  • 3
    @MuhammadUmer - Care to elaborate? – Joseph Silber Aug 21 '13 at 00:35
  • 2
    You may want to elaborate on the tilde shortcut. – Dennis Aug 21 '13 at 00:36
  • what if you have to have values named like 'itemb' not 2...so in that case that you would need to substitute all numbers with strings, and it'll become long just like that. But still is a good way to take out some logic. – Muhammad Umer Aug 21 '13 at 00:36
  • 8
    @Dennis `~` isn't a *shortcut*. It's the bitwise *NOT* operator – Phil Aug 21 '13 at 00:37
  • 4
    @MuhammadUmer - I don't get your point. The items have to be enumerated regardless of what they are. Storing them in an array is the shortest way to enumerate them. – Joseph Silber Aug 21 '13 at 00:40
  • 59
    Whilst using bitwise operators sure is sexy, is it really better than `!== -1` in any conceivable way? Isn't explicit boolean logic more appropriate than implicitly using the falsey-ness of zero? – Phil Aug 21 '13 at 00:40
  • 5
    @Phil - While I do consider the bitwise operator kind of a hack, it's pretty well known, so it's not like the code is unreadable. I really like the succinctness of the tilde, but if you don't like it, don't use it. I added the `-1` check to my answer. – Joseph Silber Aug 21 '13 at 00:42
  • 3
    I prefer to check with `>=0` which has a more relaxed condition (for when the documentation only says a negative value is returned (which may be `!==-1`) – ratchet freak Aug 21 '13 at 09:11
  • 21
    Nicely techy, but I don't like it. It's not clear at first glance what the code is doing, which makes it unmaintainable. I much prefer "Yuriy Galanter"'s answer. – Jon Rea Aug 21 '13 at 10:13
  • 5
    That's very intresting info, who knew about such beautiful answer after such a shallow question. – Vasiliy Stavenko Aug 21 '13 at 10:24
  • 2
    @JosephSilber: Is the binary representation of 32-bit integers guaranteed in JavaScript? AFAIK [ECMAScript specification](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf) does not describe it. I am afraid that relying on `~-1 == false` is not portable. – pabouk - Ukraine stay strong Aug 21 '13 at 11:12
  • 6
    If you need to explain your code to the vast majority of people who look at it, then you probably want something a little easier to understand. – Mike G Aug 21 '13 at 13:08
  • 4
    @mikeTheLiar, yes and no. The `~foo.indexOf(bar)` shortcut is a [very](http://stackoverflow.com/a/12399125/497418) [common](http://stackoverflow.com/q/10582286/497418) [way](http://stackoverflow.com/q/9316612/497418) to write `foo.contains(bar)`, in the same way that `foo || bar` is a common shorthand form of `foo ? foo : bar` – zzzzBov Aug 21 '13 at 13:22
  • 1
    @zzz Storytime: I once asked my former manager why he was using bit-wise logic instead boolean. He had no idea what I was talking about - didn't even know there was another way to do it. – Mike G Aug 21 '13 at 13:32
  • 7
    @mikeTheLiar, that's what code reviews are for. Many programmers don't know regular expressions, but that doesn't mean I should stop using them where they make the code simpler. I try to code in a way that allows future me to understand what I've written. For anyone else maintaining the code, I have to assume a base level of competency in the language in use. If the person maintaining the code doesn't have that level of competency, it's their job to learn, not my job to dumb things down. [I'm *not* trying to say it's a good idea to write overly clever code](http://tinyurl.com/y97o8yb). – zzzzBov Aug 21 '13 at 13:47
  • @JosephSilber wont the addition of `00000000000000000000000000000001 + 11111111111111111111111111111111 = 100000000000000000000000000000000 and not 000000000000000000000000000000000 notice the first digit` – Muhammad Umer Aug 21 '13 at 14:32
  • 4
    @MuhammadUmar - Nope. Since there are only 32 bits allocated for any given number, that last bit will overflow and be lost forever, resulting in a sum of 0. Read my post again. – Joseph Silber Aug 21 '13 at 14:36
  • 65
    -1 new programmers see answers like this, think it's a cool and acceptable way of coding, then in 5 years I have to maintain their code and tear my hair out – BlueRaja - Danny Pflughoeft Aug 21 '13 at 14:47
  • 3
    @BlueRaja - The way I see it, such hacks are acceptable if they're commonly used among competent programmers (like using `a || b` in place of `a ? a : b`). Since this tilde hack is pretty well known and used, I don't think you'll have to "tear your hair out" over it. I understand that this is a matter of opinion, so if you don't like, don't use it; that's why I included the other method in my answer. – Joseph Silber Aug 21 '13 at 15:11
  • 23
    This idiom is definitely not common in languages like C#, Java, or Python, which are my areas of expertise. And I just asked a few of the local Javascript experts here, and none of them have ever seen it done before; so it is clearly not as common as you claim. **It should always be avoided in favor of the much clearer and more common `!= -1`.** – BlueRaja - Danny Pflughoeft Aug 21 '13 at 16:22
  • 7
    You've sacrificed a ton of readability for brevity. I hope no one ever looks at this code except you, otherwise your original version is far superior. – Guido Anselmi Aug 21 '13 at 17:28
  • 2
    @BlueRaja-DannyPflughoeft I agree, I don't really think it's common in Javascript, either, which I've used every day for years. Bit operations are too low-level for it to easily come to mind. – Izkata Aug 21 '13 at 18:17
  • 3
    @BlueRaja-DannyPflughoeft and all - This technique is pretty well known (see [here](http://www.javascriptturnsmeon.com/the-tilde-operator-in-javascript/) & [here](http://viget.com/inspire/a-quick-pair-of-random-javascript-tips)). Even [a simple Search](https://www.google.com/search?q=javascript+tilde+indexof) would explain it. **Its preference is a matter of opinion**. That said, since so many of think it's a bad idea, I've reverted the first solution to use `>=0`, and added a big note next to the tilde solution. This is the last I have to say about this. – Joseph Silber Aug 21 '13 at 20:06
  • 2
    guys just use it if you want and not if you don't. And respect others' choice when reading their code. Not everyone can think the same way. Somethings look more organized and easy to some people and to some just the opposite. Not to mention preference also change overtime as well. – Muhammad Umer Aug 21 '13 at 21:03
  • 12
    -1 due to unnecessary bitfiddling in a language which doesn't really specify a lot about bit representations in the first place. Plus, the bulk of this answer is explaining the bitfiddling. If you have to write 20 paragraphs to explain the hack, does it REALLY save any time? – fluffy Aug 21 '13 at 21:35
  • -1 JavaScript only has a notion of a number, not an integer. See [this answer](http://stackoverflow.com/a/4703752/358464) – Bob Fincheimer Aug 22 '13 at 00:41
  • 6
    @BobFincheimer - When using bitwise operators, the numbers are *converted* to signed 32-bit integers. See [this post on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Signed_32-bit_integers): **The operands of all bitwise operators are converted to signed 32-bit integers in big-endian order and in two's complement format.**. – Joseph Silber Aug 22 '13 at 01:21
  • 3
    -1, indexOf is not supported in all browsers. Introducing browser incompatibility just for one shortcut is not good practice. – laurent Aug 22 '13 at 07:43
  • 8
    Hint: if JavaScript experts do not know a) that `indexOf` returns `-1` for lack of presence and b) what the `~` operator does, and/or cannot comprehend what `~[...].indexOf(...)` does *at the first reading*, then **they are not JavaScript experts**. – Félix Saparelli Aug 27 '13 at 21:42
  • 2
    tilde turns -1 (not in array) into 0 (false). this is totally not intuitive, it does not invert the logic. BEWARE! – Steven Lu Aug 27 '13 at 22:23
  • I have always read the `~` as "not", which causes this shortcut to be totally confusing for me – Walter Tross Aug 27 '13 at 23:16
  • This works, but is not yet an improved code. See, that reading code is terrible. Large conditional structures, indicate complexity levels below this code, there is where is the problem. Lack OO here. – Maykonn Aug 27 '13 at 23:32
  • I have a question, Does js have **or=** operator. So i could write code like this **`if ( x == 'a' ||= 'b' ||= 'c')`** . that would be so logical. And similarly having and = wont hurt either like `&&=`. – Muhammad Umer Aug 30 '13 at 19:06
  • -1 I'm a nodeJS/JS programmer and I hate bitwise operators. If I wanted to use them, I'd code in C or assembler. JS has better syntax for this things, like the more explicit, readable `!== -1`. I hope I never have to see your code anywhere. – jperelli Mar 27 '15 at 23:16
  • +-0: -1 for `~`, for adding complexity. +1 for `>= 0`, it's trivial and everyone will understand. – Andre Figueiredo Jun 03 '15 at 17:55
  • @this.lau_ The only one browsers that does not support `indexOf`are IE<9 and very first versions of Firefox. IMHO you sould have a polyfill for this anyway. – Andre Figueiredo Jun 03 '15 at 18:03
242

You can use switch statement with fall thru:

switch (test.type) {

  case "itema":
  case "itemb":
  case "itemc":
  case "itemd":
    // do something
}
Yuriy Galanter
  • 38,833
  • 15
  • 69
  • 136
  • 9
    its basically the same as the if, the index of array method is far far better – NimChimpsky Aug 21 '13 at 09:06
  • the problem with switch statement is that you need to put an explicit break to prevent fall through – Surya Pratap Aug 21 '13 at 11:42
  • 6
    @kojiro its sadly, the right answer is this, but its impossible to get attention to this instead of the awesome bitwhise-array trick. – Manu343726 Aug 21 '13 at 12:17
  • 1
    I knew this answer had to be here but I had to scroll way down to the bottom to find it. It's exactly what the switch statement was designed for and carries over to many other languages. I have found a lot of people don't know about the 'fall through' method in a switch statement. – Jimmy Johnson Aug 21 '13 at 22:37
  • 3
    This solution is the fastest one on Firefox and Safari and second fastest (after the original `||`) on Chrome. See http://jsperf.com/if-statements-test-techsin – pabouk - Ukraine stay strong Aug 22 '13 at 08:21
  • This works, but is not yet an improved code. See, that reading code is terrible. Large conditional structures, indicate complexity levels below this code, there is where is the problem. Lack OO here. – Maykonn Aug 27 '13 at 23:34
  • 3
    I think this would be awful to write in a method if you had many conditions... It if fine for a few conditions, but for more than 10 I would go for the array to keep code neat. – yu_ominae Aug 28 '13 at 00:00
  • What a weird thing... For [the same answer in the same question](http://stackoverflow.com/a/14218660/1249581) half a year ago I received a downvote :) – VisioN Sep 01 '13 at 18:02
  • @yu_ominae I can't imagine a situation in which a long array is cleaner than a long switch statement. – KOVIKO Sep 16 '13 at 18:22
  • @Koviko the case where you have to test that condition repeatedly springs to mind. Could just be a matter of taste though. I'd rather set up a list or array in the constructor. And a list has the added benefit that you can easily add or remove conditions if needed. – yu_ominae Sep 18 '13 at 05:26
  • @yu_ominae I agree that when you need to re-use those values in another place that it's smarter to have them stored somewhere rather than duplicating them. But if there is only one point of use, the array uses more memory without any added benefit to formatting. Either way, all cases need to be listed and new cases can be added just as easily. – KOVIKO Sep 18 '13 at 13:08
63

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.

Muhammad Umer
  • 17,263
  • 19
  • 97
  • 168
  • 2
    +1 for a really good post! If I understand correctly, the `switch case` is the fastest method? – user1477388 Aug 21 '13 at 20:33
  • 1
    in firefox yes, in chrome its `if ( ...||...||...)...` – Muhammad Umer Aug 21 '13 at 20:59
  • i'd go with ' ||' because if someone is on chrome, most are, they will get highest speed and if they are on ff they still will get a lot times more. – Muhammad Umer Aug 21 '13 at 21:09
  • 8
    It's faster if you really do many loops over this input, but it's *much* slower if you have one loop with very large n (number of "itemX" strings). I hacked up [this code generator](https://github.com/kojiromike/misc/blob/master/genSpeedTest.js) that you can use to verify (or perhaps refute). `obj["itemX"]` is extremely fast if n is large. Basically, what's fast depends on context. Have fun. – kojiro Aug 21 '13 at 21:53
  • perhaps you are right somewhat...take a look at this updated code/test...switch and if still win but object lookup catches up... The thing i noticed with object is that object was getting recreated again and again. When in real situation an object containing default values would be created once. Either way switch is better. – Muhammad Umer Aug 22 '13 at 03:42
  • 3
    So it's the fastest method, but *does it matter*? – congusbongus Aug 22 '13 at 04:09
  • um yeaaa sometimes speed matter a lot, like in mobile. – Muhammad Umer Aug 22 '13 at 18:38
  • off topic comment... screenshots should almost always be taken as a PNG image... ick that image is blurry! ;-) – scunliffe Aug 28 '13 at 01:46
  • its not that i think i saved with very low quality. But since it didnt matter i didnt retry – Muhammad Umer Aug 28 '13 at 02:16
  • Hint: if you put the most likely choice above the faster your code will be. Because `switch or if` wont have to keep going. – Muhammad Umer Aug 28 '13 at 17:28
  • 1
    @Mich Don't sacrifice elegance of code just for speed. This is what many many people will say to you. In the end, just use common sense. – Andre Figueiredo Jun 03 '15 at 17:50
32

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.
}
idfah
  • 1,328
  • 10
  • 16
  • 4
    this answer is the winner in terms of speed http://jsperf.com/if-statements-test-techsin – Muhammad Umer Aug 21 '13 at 15:53
  • 1
    This is also the easiest to expand when the project goes into maintenance mode (with rules such as, `(test.type == 'itemf' && foo.mode == 'detailed')`) – Izkata Aug 21 '13 at 18:19
16
var possibilities = {
  "itema": 1,
  "itemb": 1,
  "itemc": 1,
…};
if (test.type in possibilities) { … }

Using an object as an associative array is a pretty common thing, but since JavaScript doesn't have a native set you can use objects as cheap sets as well.

kojiro
  • 74,557
  • 19
  • 143
  • 201
  • How is this shorter than the normal if statement that FlyingCat is trying to shorten? – dcarson Aug 21 '13 at 00:45
  • 1
    @dcarson OP's `if` statement's conditional takes 78 characters if you remove all whitespace. Mine takes 54 if you write it like this: `test.type in {"itema":1,"itemb":1,"itemc":1,"itemd":1}`. Fundamentally, his uses four characters for every two mine use for each additional key. – kojiro Aug 21 '13 at 00:51
  • 1
    but you can do: if(possibilities[test.type]) and save a whole 2 chars! :) – dc5 Aug 21 '13 at 01:02
15
if( /^item[a-d]$/.test(test.type) ) { /* do something */ }

or if the items are not that uniform, then:

if( /^(itema|itemb|itemc|itemd)$/.test(test.type) ) { /* do something */ }
Matt
  • 20,108
  • 1
  • 57
  • 70
  • 9
    "Some people, when confronted with a problem, think 'I know, I'll use regular expressions.' Now they have two problems." - Jamie Zawinski, 1997 – Moshe Katz Aug 27 '13 at 21:58
  • 5
    @MosheKatz While I can understand people like to bandy about that quote - and people certainly do use regular expressions for wholly unsuitable things, but this is not one of them. In the case provided by the OP, this not only matches the criteria, it does so very well. Regular expressions are not inherently evil, and matching strings with well defined parameters is what it's made for. – Vala Aug 27 '13 at 22:45
  • 3
    @Thor84no Usually, I would assume that the questioner is not actually attempting to match against such a contrived example as the first case, and that the real-world matches are not so simple, in which case I don't think a RegEx is going to be the right way to do it. To put it another way, if your RegEx is just a pipe-character separated list of options, it's not any more readable than any of the other suggestions, and possibly significantly less efficient. – Moshe Katz Aug 28 '13 at 02:19
10

Excellent answers, but you could make the code far more readable by wrapping one of them in a function.

This is complex if statement, when you (or someone else) read the code in a years time, you will be scanning through to find the section to understand what is happening. A statement with this level of business logic will cause you to stumble for a few seconds at while you work out what you are testing. Where as code like this, will allow you to continue scanning.

if(CheckIfBusinessRuleIsTrue())
{
    //Do Something
}

function CheckIfBusinessRuleIsTrue() 
{
    return (the best solution from previous posts here);
}

Name your function explicitly so it immediately obvious what you are testing and your code will be much easier to scan and understand.

Fran Hoey
  • 895
  • 9
  • 18
  • 1
    Best answer I have seen here. Really, I see that people do not care about principles of good design. Just want to fix something quickly and forget to improve the code so that the system be maintainable in the future! – Maykonn Aug 27 '13 at 23:40
  • How about just commenting like `// CheckIfBusinessRuleIsTrue`? – daniel1426 Mar 13 '14 at 15:01
4

You could put all the answers into a Javascript Set and then just call .contains() on the set.

You still have to declare all the contents, but the inline call will be shorter.

Something like:

var itemSet = new Set(["itema","itemb","itemc","itemd"]);
if( itemSet.contains( test.type ){}
Guido Anselmi
  • 3,872
  • 8
  • 35
  • 58
  • 4
    That seems like an incredibly wasteful way to accomplish what the OP is trying to do. So while you _could_ include an extra 3rd-party library, instantiate an object, and the call a method on it, you probably shouldn't. – KaptajnKold Aug 21 '13 at 15:39
  • @Captain Cold: Well the OP asked for conciseness not memory footprint. Maybe the set could be reused for other operations? – Guido Anselmi Aug 21 '13 at 18:23
  • 1
    Sure, but even so: Would you in all honesty _ever_ do this yourself? If I ever saw this in the wild, I would consider it a major WTF. – KaptajnKold Aug 22 '13 at 12:05
  • 1
    Yeah you are right (I gave you the +1s) but it assumes that this check is being done nowhere else. If it is being done in several other places and/or the test changes, then the use of the Set might make sense. I leave it to the OP to choose the best solution. All that said if this was a solitary usage I would agree that using the Set would deserve the A-s Clown hat of shame. – Guido Anselmi Aug 22 '13 at 15:02
  • 2
    I actually think the chosen answer is absolutely awful and worse then using the Set as it is absolutely unreadable. – Guido Anselmi Aug 22 '13 at 15:04
2

One of my favorite ways of accomplishing this is with a library such as underscore.js...

var isItem = _.some(['itema','itemb','itemc','itemd'], function(item) {
    return test.type === item;
});

if(isItem) {
    // One of them was true
}

http://underscorejs.org/#some

jcreamer898
  • 8,109
  • 5
  • 41
  • 56
2

another way or another awesome way i found is this...

if ('a' in oc(['a','b','c'])) { //dosomething }

function oc(a)
{
  var o = {};
  for(var i=0;i<a.length;i++)  o[a[i]]='';
  return o;
}

of course as you can see this takes things one step further and make them easy follow logic.

http://snook.ca/archives/javascript/testing_for_a_v

using operators such as ~ && || ((),()) ~~ is fine only if your code breaks later on. You won't know where to start. So readability is BIG.

if you must you could make it shorter.

('a' in oc(['a','b','c'])) && statement;
('a' in oc(['a','b','c'])) && (statements,statements);
('a' in oc(['a','b','c']))?statement:elseStatement;
('a' in oc(['a','b','c']))?(statements,statements):(elseStatements,elseStatements);

and if you want to do inverse

('a' in oc(['a','b','c'])) || statement;
Muhammad Umer
  • 17,263
  • 19
  • 97
  • 168
2

Just use a switch statement instead of if statement:

switch (test.type) {

  case "itema":case "itemb":case "itemc":case "itemd":
    // do your process
  case "other cases":...:
    // do other processes
  default:
    // do processes when test.type does not meet your predictions.
}

Switch also works faster than comparing lots of conditionals within an if

unmultimedio
  • 1,224
  • 2
  • 13
  • 39
2

For very long lists of strings, this idea would save a few characters (not saying I'd recommend it in real life, but it should work).

Choose a character that you know won't occur in your test.type, use it as a delimiter, stick them all into one long string and search that:

if ("/itema/itemb/itemc/itemd/".indexOf("/"+test.type+"/")>=0) {
  // doSomething
}

If your strings happen to be further constrained, you could even omit the delimiters...

if ("itemaitembitemcitemd".indexOf(test.type)>=0) {
  // doSomething
}

...but you'd have to be careful of false positives in that case (e.g. "embite" would match in that version)

CupawnTae
  • 14,192
  • 3
  • 29
  • 60
2

For readability create a function for the test (yes, a one line function):

function isTypeDefined(test) {
    return test.type == 'itema' ||
           test.type == 'itemb' ||
           test.type == 'itemc' ||
           test.type == 'itemd';
}

then call it:

…
    if (isTypeDefined(test)) {
…
}
...
zaph
  • 111,848
  • 21
  • 189
  • 228
1

I think there are 2 objectives when writing this kind of if condition.

  1. brevity
  2. readability

As such sometimes #1 might be the fastest, but I'll take #2 for easy maintenance later on. Depending on the scenario I will often opt for a variation of Walter's answer.

To start I have a globally available function as part of my existing library.

function isDefined(obj){
  return (typeof(obj) != 'undefined');
}

and then when I actually want to run an if condition similar to yours I'd create an object with a list of the valid values:

var validOptions = {
  "itema":1,
  "itemb":1,
  "itemc":1,
  "itemd":1
};
if(isDefined(validOptions[test.type])){
  //do something...
}

It isn't as quick as a switch/case statement and a bit more verbose than some of the other examples but I often get re-use of the object elsewhere in the code which can be quite handy.

Piggybacking on one of the jsperf samples made above I added this test and a variation to compare speeds. http://jsperf.com/if-statements-test-techsin/6 The most interesting thing I noted is that certain test combos in Firefox are much quicker than even Chrome.

scunliffe
  • 62,582
  • 25
  • 126
  • 161
1

This can be solved with a simple for loop:

test = {};
test.type = 'itema';

for(var i=['itema','itemb','itemc']; i[0]==test.type && [
    (function() {
        // do something
        console.log('matched!');
    })()
]; i.shift());

We use the first section of the for loop to initialize the arguments you wish to match, the second section to stop the for loop from running, and the third section to cause the loop to eventually exit.