96

Whats the prettiest way to compare one value against multiples options?

I know there are loads of ways of doing this, but I'm looking for the neatest.

i ask because i'd hoped this was workable (it isn't, quite obviously when you look at it):

if (foobar == (foo||bar) ) {
     //do something
}
isherwood
  • 58,414
  • 16
  • 114
  • 157
thelastshadow
  • 3,406
  • 3
  • 33
  • 36
  • 2
    You could use the javascript test function like `if(/foo|bar|ow|my|javascript|works/.test( foobar )) { /*do something*/ }` This question [simular to mine](http://stackoverflow.com/questions/12743248/how-to-nest-or-statements-in-javascript) – Ron van der Heijden Feb 13 '13 at 10:31
  • I would note here that foo will not evaluate correctly, it won't check bar e.g. `1 === (2 || 1)` will return false... – Neil Mar 21 '19 at 16:04
  • 3
    A bit old thread but in ES6: if ([foo,bar].includes(foobar) { //do something } would do – Loïc V Sep 20 '21 at 10:43

8 Answers8

163

Don't try to be too sneaky, especially when it needlessly affects performance. If you really have a whole heap of comparisons to do, just format it nicely.

if (foobar === foo ||
    foobar === bar ||
    foobar === baz ||
    foobar === pew) {
     //do something
}
david
  • 17,925
  • 4
  • 43
  • 57
88

What i use to do, is put those multiple values in an array like

var options = [foo, bar];

and then, use indexOf()

if(options.indexOf(foobar) > -1){
   //do something
}

for prettiness:

if([foo, bar].indexOf(foobar) +1){
   //you can't get any more pretty than this :)
}

and for the older browsers:
( https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/IndexOf )

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
        "use strict";
        if (this == null) {
            throw new TypeError();
        }
        var t = Object(this);
        var len = t.length >>> 0;
        if (len === 0) {
            return -1;
        }
        var n = 0;
        if (arguments.length > 0) {
            n = Number(arguments[1]);
            if (n != n) { // shortcut for verifying if it's NaN
                n = 0;
            } else if (n != 0 && n != Infinity && n != -Infinity) {
                n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
        }
        if (n >= len) {
            return -1;
        }
        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
        for (; k < len; k++) {
            if (k in t && t[k] === searchElement) {
                return k;
            }
        }
        return -1;
    }
}
André Alçada Padez
  • 10,987
  • 24
  • 67
  • 120
  • 2
    `indexOf` for arrays is only provided in IE starting with version 9, so I would avoid using it until 8 gets off the market (a long ways away, unfortunately). That said, the [MDN](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf) provides sample implementation code for browsers that don't support it. – Reid Feb 02 '12 at 23:15
  • 1
    The `Array.indexOf` method is only supported in Javascript 1.6 and later, so you need a fallback for older browsers. – Guffa Feb 02 '12 at 23:17
  • IMO, this doesn't qualify as 'pretty'. It is compact, for sure, but it really doesn't read well. When you read the OP's suggestion, which is invalid but readable, this suggestion is far from obvious what is going on, and you need to think what is actually happening...that is very bad, imo. – Max Waterman May 28 '20 at 03:18
  • 9
    The new way to do it with ES6 is using `includes`: https://stackoverflow.com/questions/2430000/determine-if-string-is-in-list-in-javascript/2555311#2555311 – baptx Jul 01 '20 at 12:55
  • 1
    @baptx That should be the number one answer. So much more readable, just like Python's foo in (bar, baz). – machinekoder Jun 21 '21 at 11:42
  • Nearly a decade has passed. Would you still recommend this horrendous hack? – l33t Oct 01 '21 at 22:34
  • 1
    @l33t haha, good one. Obviously not, but wouldn't go so far... I would use [a, b, c, ...].includes(val) – André Alçada Padez Oct 13 '21 at 17:15
42

Since nobody has added the obvious solution yet which works fine for two comparisons, I'll offer it:

if (foobar === foo || foobar === bar) {
     //do something
}

And, if you have lots of values (perhaps hundreds or thousands), then I'd suggest making a Set as this makes very clean and simple comparison code and it's fast at runtime:

// pre-construct the Set
var tSet = new Set(["foo", "bar", "test1", "test2", "test3", ...]);

// test the Set at runtime
if (tSet.has(foobar)) {
    // do something
}

For pre-ES6, you can get a Set polyfill of which there are many. One is described in this other answer.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    `Set`s are still slower than native optimizations to string comparisons. Let the browser do the optimizations. People who try to outsmart the browsers *almost always* end up with much slower code. – Jack G Jun 30 '18 at 00:08
  • 2
    @JackGiffin - What are you suggesting here? The first part of my answer is just the simplest comparison and the JS engine can optimize that however it likes. The second part of my answer that uses a `Set` is targeted at the case where you have lots of values to compare to (hundreds or thousands). I don't understand what you are suggesting instead of these or what you think is wrong with these suggestions? – jfriend00 Jun 30 '18 at 00:33
  • 1
    How is Set better than common Array: `if(['foo', 'bar'].includes(value))`? – DIES Oct 06 '20 at 19:03
  • 6
    @DIES - A `Set` uses a hash table lookup, whereas, `.includes()` uses a linear search. When you have more than few items in the collection, the Set should be a lot faster to see if an item is in the `Set`. Plus, `.add()` for a `Set` prevents duplicates. – jfriend00 Oct 06 '20 at 20:04
  • Set.has is definitely faster than Array.includes when working with huge data. You can get away with Array.includes when working with small dataset. – Dale Ryan Mar 11 '23 at 04:55
24

You can use a switch:

switch (foobar) {
  case foo:
  case bar:
    // do something
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
18

Just for kicks, since this Q&A does seem to be about syntax microanalysis, a tiny tiny modification of André Alçada Padez's suggestion(s):

(and of course accounting for the pre-IE9 shim/shiv/polyfill he's included)

if (~[foo, bar].indexOf(foobar)) {
    // pretty
}
lucideer
  • 3,842
  • 25
  • 31
13

Why not using indexOf from array like bellow?

if ([foo, bar].indexOf(foobar) !== -1) {
    // do something
}

Just plain Javascript, no frameworks or libraries but it will not work on IE < 9.

Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474
1

(foobar == foo || foobar == bar) otherwise if you are comparing expressions based only on a single integer, enumerated value, or String object you can use switch. See The switch Statement. You can also use the method suggested by André Alçada Padez. Ultimately what you select will need to depend on the details of what you are doing.

david
  • 17,925
  • 4
  • 43
  • 57
JamieSee
  • 12,696
  • 2
  • 31
  • 47
  • Already mentioned three times above. At stack overflow, you are expected to only post solutions that are not among the already existing answers to a question. – Jack G Jun 30 '18 at 00:13
  • @JackGiffin - If you look at the time stamps, there were not multiple other answers posted before this one that showed this solution. Answers here are not necessarily displayed in posting order. Only my answer that shows this appears to be before it and that is only 3 seconds before it so not something this author would have seen. The accepted answer even came after this one. Again, I'm not sure why you're bashing people over a 6 year old answer. – jfriend00 Jun 30 '18 at 00:55
  • @jfriend00 You're right! I studied all the time stamps, and david is the fraud, not JamieSee. JamieSee got his answer out 14 minutes before david, and David has the exact same answer, but david got the credit, and JamieSee did not. Let us upvote JamieSee's more justified answer. – Jack G Jul 03 '18 at 22:52
  • @JackGiffin - It's not only about who gets there first. There are other aspects to a good answer besides just whether it has the right content in it somewhere such as how clearly it's written, how well the explanation is done, etc... The OP even comments on david's answer that it's the "most legible". There are even times when it's appropriate to write another answer that isn't all that unique just because none of the existing answers do a very good job of presenting and explaining things. I'm not implying anything about that in this case, just that being first isn't the only criteria. – jfriend00 Jul 04 '18 at 00:18
  • @JackGiffin - The checkmark is supposed to go to the best answer. It's a contest to see who can write the best answer. Multiple submissions are allowed. Straight copying without adding something worthwhile is frowned on, but attempting to write a better answer that explains things better or explains some new aspects is not only allowed but desired. Again, I'm not implying anything about this particular case, just commenting in general. – jfriend00 Jul 04 '18 at 00:21
0

I like the pretty form of testing indexOf with an array, but be aware, this doesn't work in all browsers (because Array.prototype.indexOf is not present in old IExplorers).

However, there is a similar way by using jQuery with the $.inArray() function :

if ($.inArray(field, ['value1', 'value2', 'value3']) > -1) {
    alert('value ' + field + ' is into the list'); 
}

It could be better, so you should not test if indexOf exists.

Be careful with the comparison (don't use == true/false), because $.inArray returns the index of matching position where the value has been found, and if the index is 0, it would be false when it really exist into the array.

Community
  • 1
  • 1
Joel Barba
  • 83
  • 4
  • Please don't use jQuery (unless that is, you do want slow code and slow page load speeds in which case go for it -- I am noone to stop insanity) – Jack G Jun 30 '18 at 00:12