I'm checking a variable, say foo, for equality to a number of values. For example,

if( foo == 1 || foo == 3 || foo == 12 ) {
    // ...
}

The point is that it is rather much code for such a trivial task. I came up with the following:

if( foo in {1: 1, 3: 1, 12: 1} ) {
    // ...
}

but also this does not completely appeal to me, because I have to give redundant values to the items in the object.

Does anyone know a decent way of doing an equality check against multiple values?

Solution 1

You could use an array and indexOf:

if ([1,3,12].indexOf(foo) > -1)

Solution 2

In ECMA2016 you can use the includes method. It's the cleanest way I've seen. (Supported by all major browsers)

if([1,3,12].includes(foo)) {
    // ...
}

Solution 3

Using the answers provided, I ended up with the following:

Object.prototype.in = function() {
    for(var i=0; i<arguments.length; i++)
       if(arguments[i] == this) return true;
    return false;
}

It can be called like:

if(foo.in(1, 3, 12)) {
    // ...
}

Edit: I came across this 'trick' lately which is useful if the values are strings and do not contain special characters. For special characters is becomes ugly due to escaping and is also more error-prone due to that.

/foo|bar|something/.test(str);

To be more precise, this will check the exact string, but then again is more complicated for a simple equality test:

/^(foo|bar|something)$/.test(str);

Solution 4

Now you may have a better solution to resolve this scenario, but other way which i preferred.

const arr = [1,3,12]
if( arr.includes(foo)) { // it will return true if you `foo` is one of array values else false
  // code here    
}

I preferred above solution over the indexOf check where you need to check index as well.

includes docs

if ( arr.indexOf( foo ) !== -1 ) { }

Solution 5

This is easily extendable and readable:

switch (foo) {
    case 1:
    case 3:
    case 12:
        // ...
        break

    case 4:
    case 5:
    case 6:
        // something else
        break
}

But not necessarily easier :)

Solution 6

You can write if(foo in L(10,20,30)) if you define L to be

var L = function()
{
    var obj = {};
    for(var i=0; i<arguments.length; i++)
        obj[arguments[i]] = null;

    return obj;
};

Solution 7

var a = [1,2,3];

if ( a.indexOf( 1 ) !== -1 ) { }

Note that indexOf is not in the core ECMAScript. You'll need to have a snippet for IE and possibly other browsers that dont support Array.prototype.indexOf.

if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(searchElement /*, fromIndex */)
  {
    "use strict";

    if (this === void 0 || 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)
        n = 0;
      else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
        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;
  };
}

Solution 8

Also, since the values against which you're checking the result are all unique you can use the Set.prototype.has() as well.

var valid = [1, 3, 12];
var goodFoo = 3;
var badFoo = 55;

// Test
console.log( new Set(valid).has(goodFoo) );
console.log( new Set(valid).has(badFoo) );

Solution 9

I liked the accepted answer, but thought it would be neat to enable it to take arrays as well, so I expanded it to this:

Object.prototype.isin = function() {
    for(var i = arguments.length; i--;) {
        var a = arguments[i];
        if(a.constructor === Array) {
            for(var j = a.length; j--;)
                if(a[j] == this) return true;
        }
        else if(a == this) return true;
    }
    return false;
}

var lucky = 7,
    more = [7, 11, 42];
lucky.isin(2, 3, 5, 8, more) //true

You can remove type coercion by changing == to ===.

Solution 10

If you have access to Underscore, you can use the following:

if (_.contains([1, 3, 12], foo)) {
  // ...
}

contains used to work in Lodash as well (prior to V4), now you have to use includes

if (_.includes([1, 3, 12], foo)) {
  handleYellowFruit();
}

Solution 11

For a larger list of values that you compare with often, it is likely more optimal to first construct a Set and use Set#has for a constant time check rather than Array#includes which runs in linear time.

const values = new Set([1, 2, 12]);
if(values.has(foo)){
   // do something
}

Solution 12

I simply used jQuery inArray function and an array of values to accomplish this:

myArr = ["A", "B", "C", "C-"];

var test = $.inArray("C", myArr)  
// returns index of 2 returns -1 if not in array

if(test >= 0) // true

Solution 13

This is a little helper arrow function:

const letters = ['A', 'B', 'C', 'D'];

function checkInList(arr, val) {
  return arr.some(arrVal => val === arrVal);
}

checkInList(letters, 'E');   // false
checkInList(letters, 'A');   // true

More info here...

Solution 14

Using the ES6 syntax you can do:

Object.prototype.in = function (...args) {
  return args.includes(this.valueOf());
}

which incidentally also checks for deep equality. The valueOf() method is needed as this is an object.

Solution 15

For posterity you might want to use regular expressions as an alternative. Pretty good browser support as well (ref. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#Browser_compatibility)

Try this

if (foo.toString().match(/^(1|3|12)$/)) {
    document.write('Regex me IN<br>');
} else {
    document.write('Regex me OUT<br>');
}