DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Jason has posted 22 posts at DZone. View Full User Profile

Using JavaScript's "in" Operator To Simplify Redundant Logical ORs

11.18.2008
| 77089 views |
  • submit to reddit
        Example of using the JavaScript "in" operator to reduce a series of logical ORs. Obviously this can be expanded, but the point is present.

The "in" operator construct (x in y -or- prop in object) checks to see if x is a property of y.

https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/in_Operator

if ( foo == "bar" || foo == "foobar" || foo == "foo" )
{
 //...
}
// can be written as
if ( foo in { bar:1, foobar:1, foo:1 } )
{
 //...
}
    

Comments

Royston Shuffle... replied on Mon, 2012/11/26 - 5:36am

Unfortunately this code will also return true if  'foo' is the word "constructor".  Your plain JavaScript object implicitly inherits from the basic object prototype, which contains a property called 'constructor'. i.e.

"constructor" in {};    // returns true!

This is covered in detail in 'JavaScript - The Good Parts ' if you want the gory bits.

You could use 'hasOwnProperty' to check correctly instead of 'in', but that's kinda defeating the purpose.


Snippets Manager replied on Sat, 2010/04/03 - 3:08pm

Notice the curly braces too. That denotes object literal syntax, thus making bar, foobar, and foo attributes of an anonymous object that only gets used by the in comparison. The one is just to give them a value to comply with the object literal syntax. A better explanation is available at the mozilla dev center

Snippets Manager replied on Wed, 2010/03/10 - 4:09pm

This is absolutely frikkin' awesome! Could you please tell me what the :1 is for after each of the comparison values?

Snippets Manager replied on Fri, 2012/04/27 - 6:58am

@Chraw: This code is not valid Javascript. To initialize an array with specific indexes, you should make : var arr= new Array(); arr["bar"]=1; arr["foobar"]=1; arr["foo"]=1; if("foobar" in arr){ (...) } But arrays are not provided for being used as sets, and I recommend not to use them that way. Another solution which has the advantage of using native arrays is using indexOf: if (["bar","foobar","foo"].indexOf(foo)>=0) { //... } or with a helper: function isInArray(val,arr){ return arr.indexOf(val)>=0; } if(isInArray(foo,["bar","foobar","foo"])){ (...) }

Snippets Manager replied on Sat, 2012/04/28 - 1:06pm

I need to correct one thing about my previous posting. My copy of O'Reilly's "JavaScript: The Definitive Guide" is old and doesn't document Array.indexOf(). Based on that I stated, wrongly, that Array has no indexOf() method. But I just found Array.indexOf() documented at http://www.w3schools.com/jsref/jsref_indexof_array.asp. Mea culpa! But I stand behind the rest of my analysis. Using an Array to do this implies looping through all the Array values and doing a string compare on each loop iteration. The fact that the loop and compare are hidden inside the implementation of Array.indexOf() may make it easier to write the code, but it still requires the CPU to do a lot more computing than doing it with a hashtable. The specific problem is that if you use an Array, the compute time to determine that a particular value is not in the Array increases as the number of Array elements increases, whereas the compute time if you use a hashtable (i.e. Object properties), is the same regardless of how many properties the Object has.

Snippets Manager replied on Sat, 2012/04/28 - 1:06pm

sylvainpv's posting has two important mistakes: #1 arr["bar"]=1; ... This is not legal JavaScript syntax because arrays only allow integer indices. #2 ["bar","foobar","foo"].indexOf(foo) This is not legal JavaScript because Array has no indexOf() method. indexOf() is a method of String. There seems to be a significant amount of confusion here between JavaScript Objects and Arrays, most likely due to the fact that the same syntax: x[y]=value; can be used regardless of whether x is an Object or an Array. But if the value x holds is an Array, then y must be a non-negative integer, whereas if the value x holds is an Object, then y must be a string. Both Objects and Arrays may be declared as initialized constants, but their syntax is different. To assign an initialized Array constant to the variable x: x = [ val1, val2, val3 ]; which is equivalent to: x = new Array(); x[0] = val1; x[1] = val2; x[2] = val3; If it's an initialized Object constant rather than an initialized Array constant you want to assign to x: x = { prop1:val1, prop2:val2, prop3:val3 }; which is equivalent to: x = new Object(); x["prop1"] = val1; x["prop2"] = val2; x["prop3"] = val3; and also equivalent to: x = new Object(); x.prop1 = val1; x.prop2 = val2; x.prop3 = val3; An initialized Object is exactly what you want here. The reason is NOT because it makes the syntax nicer. It's because of what happens at runtime. The: if ( foo == "bar" || foo == "foobar" || foo == "foo" ) above requires several string compares. If foo doesn't contain any of the values in the list, it requires 3 compares to determine that. If there were 10 values to be tested, it would require 10 compares to determine that foo doesn't contain any of those values. To do this using an array would require the same number of compares as doing it using logical ORs. The compares would have to be done in a loop inside sylvainpv's isInArray() function. His proposed implementation of isInArray() won't work because, as I noted above, indexOf() is a method of String, not Array. And even if Array DID have an indexOf() method (similar to PHP's in_array() function), all the compares would still have to be done. They'd just be hidden inside our hypothetical Array.indexOf() method. The reason why doing this using Object properties is interesting is that the computation required involves a little arithmetic followed by JUST ONE comparison. That's because an Object is implemented as a hashtable. A hashtable is a chunk of memory that holds pointers to values. Initially all the pointers are set to zero to indicate they don't contain any value. To index into a hashtable, you take the characters in the key and run them through a hash function to turn them into an integer no larger than the number of pointers in the hashtable. The output of the hash function is a pointer to the location in the hashtable that contains a pointer to the value associated with that key. The hash function is a quick computation. It's called a "hash" because what it does to the key is the mathematical equivalent of what you do to corned beef to make corned beef hash! This isn't the whole story because it's entirely possible that multiple keys could map to the same location in the hashtable. And provision has to be made in the design of the hashtable to determine when a collision has happened and make alternate arrangements. But unless your hashtable is pretty full, most of the time you won't encounter a collision. So, from the perspective of compute time, a hashtable is usually a big win. It's so handy to have hashtable as a built-in datatype in a language that it's in both PHP and JavaScript. But to use them effectively, you need to understand more than just the superficial syntax.

Snippets Manager replied on Wed, 2011/03/16 - 6:20am

{ bar:1, foobar:1, foo:1 } This is the JSON manner of writing code. With this code you make a JavaScript Object. You can make a JSON array too, you can do that with the same manner but now not with the {}-signs. You can make an array with the []-signs. So this is an array: [ bar:1, foobar:1, foo:1 ]