Last active
December 31, 2015 04:29
-
-
Save webdesserts/7934890 to your computer and use it in GitHub Desktop.
Testing for the presence of an item in an array with `.indexOf()` and the `~` bitwise operator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var desserts = ['gelato', 'tiramisu', 'double chocolate volcano cake'] | |
// indexOf() is a nifty little Array method that returns the index of the element passed | |
desserts.indexOf('gelato') //=> 0 | |
// One oditty of it is that it returns -1 if there is no match. | |
desserts.indexOf('meatloaf') //=> -1 | |
// So the question arrises, "why -1"? | |
// well let's say we want to test if 'gelato' exists in the desserts array. | |
// normally we would have to do something like this: | |
var exists = false; | |
desserts.forEach(function(item) { | |
if ('gelato' === item) exists = true; | |
}) | |
// well it turns out we can use this "one weird trick" to do the same thing with indexOf() | |
// So why doesn't indexOf() return null or something similar? | |
// Well as we know arrays have 0 based indexes, so if we tried | |
// to coerce the index to a boolean, the first item of the array | |
// would always return false. | |
teramisu = desserts.indexOf('teramisu') //=> 1 | |
Boolean(teramisu) //=> true | |
gelato = desserts.indexOf('gelato') //=> 0 | |
Boolean(gelato) //=> false | |
// So unfortunately we wouldn't be able to use the index directly in a conditional | |
// This is where the bitwise ~ operator comes in. | |
// ~ is what is known as the "bitwise NOT" operator | |
// The ~ operator essentially returns -(n+1) | |
~1 //=> -2 | |
~5 //=> -6 | |
~0 //=> -1 | |
~-5 //=> 4 | |
~-1 //=> 0 | |
// note that last one there. That's the same as... | |
-(-1+1) | |
//or | |
-(0) | |
// this means that unlike any other number, -1 converts to 0 which so | |
// happens to be the only number that coerces to false. | |
// Aha! See where this is going now? | |
// So let's try using this on our indexOf() results. | |
Boolean(~desserts.indexOf('gelato')) //=> true | |
Boolean(~desserts.indexOf('teramisu')) //=> true | |
Boolean(~desserts.indexOf('meatloaf')) //=> false | |
// Let's expand that to see what's going on behind the scenes | |
index = desserts.indexOf('gelato') //=> 0 | |
num = ~index //=> -1 from -(0+1) | |
Boolean(num) //=> true | |
index = desserts.indexOf('teramisu') //=> 1 | |
num = ~index //=> -2 from -(1+1) | |
Boolean(num) //=> true | |
index = desserts.indexOf('meatloaf') //=> -1 | |
num = ~index //=> 0 from -(-1+1) | |
Boolean(num) //=> false | |
// so whenever indexOf() can't find an item in the array, it | |
// returns -1 which the ~ operator can convert to 0 which is | |
// coerced to false, while 0 is safely converted to -1 and | |
// coerced to true. | |
// This allows simple one liner tests for the existance of an item in an array | |
if (~desserts.indexOf(item)) eatDessert(item) | |
// pretty cool, huh? | |
// For more information on WHY the ~bitwise operator works | |
// the way it does, I would suggest checking out the MDN article on the ~ operator | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#.7E_(Bitwise_NOT) | |
// And this talk on floating point numbers by Bartek Szopka | |
// http://t.co/Yiu5HfRoER |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment