25

I was reading this blog post which mentioned using:

!!~ 

I have no idea what this does? at first I thought it would give an error, but the code below does run:

var _sessions = [
    "_SID_1",
    "_SID_2",
    "_SID_3",
    "_SID_4"
];

if(!!~_sessions.indexOf("_SID_5")) {
    console.log('found');
} else {
    console.log('!found');
}

output:

node test.js 
!found
Alfred
  • 60,935
  • 33
  • 147
  • 186
  • There are good answers below, but for readability, I would never use this. Use indexOf !== -1 instead. – jgroenen Nov 28 '12 at 11:24
  • 1
    The whole blog post seems to be full of vague "advice" with no substance. I really wouldn't pay any attention to it tbh. There are far more useful resources out there. – Vala Nov 28 '12 at 11:27
  • 1
    I've posted a comment (currently awaiting moderation) on the blog post asking for a source or some benchmark data on the assertion that `!!~` allows for a "quick lookup". I'll update my answer with any more details I discover. – James Allardice Nov 28 '12 at 11:43
  • Oops little bit double question, but it is also used in for example mongoose => http://stackoverflow.com/q/10582286/11926. But the search did not return this immediately. Still not I believe? you can not search for !!~ from stackoverflow search or can you? – Alfred Nov 28 '12 at 23:28
  • Also, check this: http://stackoverflow.com/questions/1744310/how-to-fix-array-indexof-in-javascript-for-ie-browsers – jgroenen Jan 23 '13 at 10:10

3 Answers3

28

~ is the bitwise not operator. It inverts the bits of its operand. ! is the logical not operator. The bitwise not operator will return 0 when applied to -1, which is what indexOf returns when the value is not found in the array. Since 0 evaluates to false, doubly negating it will simply return false (a boolean value, rather than a numeric one):

var index = _sessions.indexOf("_SID_5");
console.log(~index); // 0
console.log(!~index); // true
console.log(!!~index); //false

The bitwise not operator will return a value less than 0 for any other possible value returned by indexOf. Since any other value will evaluate to true, it's just a shorthand method (kind of... they are both the same number of characters!) of checking whether an element exists in an array, rather than explicitly comparing with -1:

if (_sessions.indexOf("_SID_5") > -1) {
    // This would work the same way
}

Update

With regards to the performance of this, it appears (in Chrome at least) to be marginally slower than the more common comparison with -1 (which itself is marginally slower than a comparison with 0).

Here's a test case and here's the results:

enter image description here

Update 2

In fact, the code in your question can be shortened, which may have been what the author was attempting to do. You can simply remove the !!, since the ~ will always result in 0 or below (and 0 is the only value that will evaluate to false):

if (~_sessions.indexOf("_SID_5")) {
    // This works too
}

However, in a slightly different situation it could make sense to add in the ! operators. If you were to store the result of the bitwise operator in a variable, it would be a numeric value. By applying the logical not operator, you get a boolean value (and applying it again ensures you get the correct boolean value). If for some reason you require a boolean value over a numeric one, it makes a little bit more sense (but you can still just use the normal comparison with -1 or 0):

var inArray = !!~_sessions.indexOf("_SID_5");
console.log(typeof inArray); // boolean
Kevin K
  • 9,344
  • 3
  • 37
  • 62
James Allardice
  • 164,175
  • 21
  • 332
  • 312
  • Aha I doubt this will result in quick(er) lookup. It only makes the code that much harder to read? – Alfred Nov 28 '12 at 11:16
  • 1
    That really is one of the least readable ways I can imagine this being done. What happened to `x.indexOf(y) >= 0` or to achieve exactly this `x.indexOf(y) != -1`? Thanks for the explanation though. – Vala Nov 28 '12 at 11:18
  • 1
    @Alfred - You're welcome :) And you're correct, it results is slightly slower lookup (in Chrome at least). I can't see any good reason to use it over a normal comparison to `0` or `-1`. – James Allardice Nov 28 '12 at 11:26
  • @Alfred - I've updated the answer again with some additional comments. The code in your question can actually be shortened, which may make a bit more sense. But even so, I would stick with the usual comparison! – James Allardice Nov 28 '12 at 11:38
  • I forget where I heard it, but bitwise operators in javascript should be avoided because they not only don't make the code faster, but they make it slower. The underlying representation of numbers in javascript is done with 64 bit floats, but to perform the bitwise functions, they have to be converted to 32 ints, and then back again. – mowwwalker Nov 28 '12 at 14:15
  • @Walkerneo - Yes, that's exactly right. It's detailed [in the spec](http://es5.github.com/#x11.4.8). And as the benchmark screenshot in my answer shows, the bitwise version is definitely slower. – James Allardice Nov 28 '12 at 14:25
  • good to know, there is bit extended tests http://jsperf.com/bitwise-not-vs-gt-indexof/2 bit surprised by IE9, though gt -1 winner – dmi3y Nov 28 '12 at 16:16
7

Donald Knuth: "[...] premature optimization is the root of all evil"

For the sake of readability: please use

.indexOf !== -1
jgroenen
  • 1,332
  • 1
  • 8
  • 13
  • I agree :). I read that and thought what the heck is that? But now that I know I will never use that form. – Alfred Nov 28 '12 at 11:27
  • Never hurts to know what it does, but you need to know about two's complement to really understand this. – jgroenen Nov 28 '12 at 11:31
  • Selective quotation, of a *clause*, not even a sentence, from a whole paragraph which contains some very important qualifications. A much-abused saying. – user207421 Jan 31 '16 at 23:56
  • "Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%." From the code snippet, I strongly doubt this piece of code is critial. – jgroenen May 06 '16 at 18:30
  • http://c2.com/cgi/wiki?PrematureOptimization – jgroenen May 06 '16 at 18:34
5

This explains it well:

The tilde operator in Javascript

Mixing the two NOT operators together can produce some interesting results:

!~(-2) = false

!~(-1) = true

!~(0) = false

!~(1) = false

!~(2) = false

So this just checks if the value equals -1 or not, and indexOf returns -1 if it does not find a match

Community
  • 1
  • 1
ppeterka
  • 20,583
  • 6
  • 63
  • 78