6

I was just wondering if there is some JS shorthand for something like this:

if (x != 1 && x != 2) do stuff;

Does such a beast exist? Instead, I want to say something like this:

if (x != 1:2) do stuff;

Ian
  • 46,701
  • 13
  • 94
  • 107
Slink
  • 253
  • 1
  • 3
  • 14
  • 1
    On larger ranges it would make sense to do (x < 1 || x > 2), but other than that can't think of alternatives. That's assuming they're integers and you don't have to say take 1.5 into account. – PeterJ Dec 14 '12 at 02:56
  • 3
    You can do some hacky stuff with the `in` operator, but no there isn't really something like what you describe. `lhs in rhs` will return whether lhs is a property of rhs – Anthony Sottile Dec 14 '12 at 02:58
  • 1
    if you're looking to include/exclude from the contents of a list, use Array.indexOf – ocodo Dec 14 '12 at 03:36
  • Wow, folks really ran with this. Well, it was just a theory-and-technique type of question. I really like to see the musings and concepts posted here. It provides more insight. The official answer is NO, that syntax functionality does not exist in standard JavaScript. Also, I don't think it exists in jQuery, but I'm not sure. It may exist in another JS library. – Slink Dec 14 '12 at 22:38
  • A switch statement seems to be the most appropriate option, which is what I was going to implement anyway. – Slink Dec 14 '12 at 22:46
  • However it would be nice to say stuff like `if (x == 1 OR 2, || x > 5 AND < 7, && y != 3 AND/OR 6) dostuff;` However, it is much harder to misinterpret (for the programmer AND for the parser/compiler) when you keep it broken down to `if ((x == 1 || x == 2) || (x > 5 && x < 7) && (y != 3 || y != 6))` (not sure if i copied that properly) – Slink Dec 14 '12 at 22:54

6 Answers6

5

No, there is no such shorthand.

You can use a switch if you don't want to repeat the variable:

switch (x) {
  case 1:
  case 2: break;
  default: do stuff;
}

Another alternative would be to look for the value in an array:

if ([1, 2].indexOf(x) == -1) do stuff;

However, the Array.indexOf doesn't exist in all browsers, so you may need a fallback which you can for example find on the Mozilla Array.indexOf documentation page.

Guffa
  • 640,220
  • 96
  • 678
  • 956
  • 1
    Shorter would be `if(!!~[1,2].indexOf(x))` – helly0d Dec 14 '12 at 03:07
  • 6
    @helly0d: Yes, that is perfect; it's both slow and unreadable. ;) – Guffa Dec 14 '12 at 03:24
  • 1
    Just what he is looking for :). Never try to shorthand anything if it's just for the sake of writing a few characters less in a code. There are a lot of hacks but most of them are costly. – helly0d Dec 14 '12 at 03:27
  • @helly0d Why bother with the `!!`? It'll already evaluate to something that works correctly for an `if` statement – Ian Dec 14 '12 at 03:51
  • @Ian Besides the fact that it was posted as a joke, the `!!` was intended for other uses than `if` statement and it forces the conversion to `true` or `false` for these other cases. – helly0d Dec 14 '12 at 03:54
  • @helly0d Haha couldn't tell if you were joking before Guffa's comment :) But yeah, I knew what that does, I just thought it could be omitted because it's not being stored or used anywhere else. Anyways, it doesn't matter, as it was a joke – Ian Dec 14 '12 at 03:56
2

no that doesn't exist, and that is good so! only in less precise natural language such a thing exists. which can lead to confusion.

AlexWien
  • 27,247
  • 5
  • 48
  • 78
1

There are two ways I can think of.

Case 1:

if ([1, 2].indexOf(x) < 0) // do stuff

Case 2:

I wouldn't recommend this way:

if (!(x in {1:0, 2:0})) // do stuff

Stepwise:

  1. We create an object with the numbers to compare against as keys: {1:0, 2:0}
  2. We use the in operator to check whether the value of x is a key of the object.
  3. We negate the resultant boolean using ! because we want to check for inequality.

I suggest you look at CoffeeScript instead. It has chained comparisons which will allow you to do something like this:

if (1 <= x <= 2) // do stuff

It's not the same as your condition, but you might find it interesting.

Aadit M Shah
  • 67,342
  • 26
  • 146
  • 271
  • Instead of `0`'s for the object's values (Case 2), why not empty strings? Probably wouldn't make that much of a difference, but less memory/space used. Also, it should be noted that using Case 2, it performs a comparison like `==`, so `===` is not possible – Ian Dec 14 '12 at 04:01
  • And I guess it's just me, but I would definitely recommend Case 2. It may not be as readable, but it would be a much easier lookup than `indexOf` (at least noticeable for larger amounts of items to match against), and is supported in all browsers. – Ian Dec 14 '12 at 05:48
  • Awesome to see this stuff. Unfortunately, all of it is clunky. The answer is "nope! you have to use this:`if (variable-comparator-value and/or variable-comparator-value) dostuff` (Pseudocode) – Slink Dec 14 '12 at 22:42
1
var a = 4;
if ([1,2,3,5,7,8,9,0,10,15,100].indexOf(a) == -1) console.log(a);

Will log 4 to console because 4 is not present on the list.

Jani Hyytiäinen
  • 4,804
  • 32
  • 45
  • Note though that the `Array.indexOf` doesn't exist in all browsers, for example IE8 and earlier. – Guffa Dec 14 '12 at 03:26
  • Just add Array.prototype.indexOf = function(obj, start) { for (var i = (start || 0), j = this.length; i < j; i++) { if (this[i] === obj) { return i; } } return -1; } And then you have it. – Jani Hyytiäinen Dec 14 '12 at 03:38
  • At least check if there already is an implementation before replacing it with one that is worse... – Guffa Dec 14 '12 at 03:45
  • @Guffa And then you have it. Haha – Ian Dec 14 '12 at 03:52
1

x!=1 && x!=2 is shorthand for the browser- if the first part is false it quits right away. No code you can wrap it in that evaluates both expressions could be nearly as efficient.

kennebec
  • 94,076
  • 30
  • 99
  • 125
0

There would be nothing wrong with writing your own function to add a method to a given object. There are a variety of ways to do that, by extending prototypes or using a namespace. Example syntax might be:

if (!x.equals('1||2')) { /* do your stuff */ }
// the custom method '.equals' would extend a STRING, and return true or false

Another example:

if (π.is(x,['1||2'])) { /* do your stuff */ }
// custom object "π" has a method "is" which checks whether x is 1 or 2, and returns true or false

There are so many ways to do this. Some are frowned upon for very good reasons (extending core object prototypes, for example, is not always ideal as it could impact other libraries and freak people out), and of course there is always the risk of over-engineering. Tread carefully.

Minor note: I intentionally put the logical operator '||', with the idea that the underlying function might be flexible and take other operators, such as '&&' or '!' etc.

Joshua
  • 3,605
  • 1
  • 24
  • 32
  • 1
    The expression `1||2` will always express `1`. You're losing information. – Aadit M Shah Dec 14 '12 at 03:23
  • @AaditMShah edited. The comment tags got stripped for some reason on post. – Joshua Dec 14 '12 at 03:24
  • Is there any reason you wouldn't rather use `[1, 2].indexOf(x) < 0`? – Aadit M Shah Dec 14 '12 at 03:26
  • @AaditMShah Nope. Your answer is on point. Mine probably stretches a bit by trying to be extensible. – Joshua Dec 14 '12 at 03:29
  • However, writing my own func would be the only way to parse that syntax in the way of natural speech (which inevitably becomes ambiguous and confusing in certain situations). "Am I good or bad?" "UNEXPECTED INPUT 'BAD' NOT RECOGNIZED" – Slink Dec 14 '12 at 22:45