This ain’t your Jessie J, Ariana Grande, Nicki Minaj JavaScript. No, it may not have the body of an hourglass, but it might have a little something in common with it! Want to find out what in the world this nonsensical talk is about and actually earn some knowledge about !! in JavaScript, then follow the link to get your learn on.
Not Not JavaScript
!! JavaScript Operator
I’m sure my co-hosts Joe and Michael will get a kick out of “Not Not Javascript” If you’ve listened to any of the podcast episodes, you’ll know exactly what I’m talking about! Heck, they’d probably tell me to drop one of the Not’s.
First, let’s clear one thing up – !! is not an operator – it’s simply calling the “not” operator two times in a row. Now that that’s behind us, let’s get into the meat of this thing.
Have you ever seen someone do something like this:
1 2 3 |
var someFunction = function(someArg){ var myVar = someArg || {}; } |
You’ll notice the someArg || {}…
Essentially all that’s saying is if someArg is “truthy” then assign the value of someArg to myVar, otherwise, assign an empty Object to myVar. If you’ve been programming JavaScript for very long, you’ve seen this sprinkled throughout code everywhere. It’s a nice shorthand for assignment when variables are undefined, null or the like.
Recently, I’ve been seeing code that looks like this:
1 2 3 |
var someFunction = function(someArg){ var myVar = !!someArg ? someArg : {}; } |
So what’s that doing differently? Well, it’s essentially telling Javascipt to explicitly cast the value of someArg to an inverse boolean with the first ! and then to flip the boolean with the second !. So essentially if someArg was actually a “true” boolean, then the first ! would have converted someArg to false, and the second ! would have turned it back to true. That’s not all that useful for a value that’s already a boolean, but for something that’s an unknown type, it can help you determine whether it was a truthy value.
Now, with all that said – does the !! actually buy you anything? Take the following code for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// JavaScript Truthy or Inverse of Falsey var anUndefinedVariable; var truthy = { "undefined":anUndefinedVariable, "null":null, "true value":true, "false value":false, "true string":"true", "false string":"false", "-2":-2, "-1":-1, "0":0, "1":1, "2":2, "-2 string":"-2", "-1 string":"-1", "0 string":"0", "1 string":"1", "2 string":"2", "empty string":"", "non-empty string":"test string", "function":function(){}, "object":{}, "array":[], "empty string as object":new String(""), "non-empty string as object":new String("some string"), "0 as number object":new Number(0), "1 as number object":new Number(1), "2 as number object":new Number(2), "-1 as number object":new Number(-1), "true as boolean object":new Boolean(true), "false as boolean object":new Boolean(false) } // Now let's see what will actually happen with the above values for(var i in truthy){ console.log(i); console.log(truthy[i]); if(truthy[i]){ console.log("implicit conversion: true"); } else{ console.log("implicit conversion: false"); } console.log("inverse falsey: " + (!!truthy[i])); } |
Looking at the code above, would you expect the “if” statements to output anything different than the !! version of the same value? If you said, no, then you’d be correct! I’ve put together a Plunker so you can see exactly what’s output to the debug console. Please note, in order to see this, you’ll want to be running in a browser that gives you a debug console with developer tools you can inspect.
http://plnkr.co/edit/enWREQwnDkGjQJTvRFnE?p=preview
So Why Use !!
Now there’s a great question. Why indeed would you use !! if it does the same exact thing as leaving it off in the first place?! There has to be a reason right? I mean, maybe people just like to see exclamation marks everywhere! Maybe it gets them excited about coding!
PERFORMANCE…
I was shocked myself to find out that the !! is WAYYYYYY faster than the non-!! version. In Chrome, it was about 2x as fast. In Safari (on Mac) it was about 3x as fast! In Firefox it was just under 2x as fast. Sorry for those out there hanging on the edge of your seat for Internet Explorer, I didn’t test that one…my Mac doesn’t like it! 🙂
Those are pretty significant differences in execution times. Here’s the code so you can see how I tested:
So, if you want to be proven wrong, put your article on Reddit! 🙂 Here’s the deal. I had a flaw in my original test below which was doing an == comparison rather than an === which means that one of the two tests was actually doing another cast on the variable which caused the performance difference. I’ve updated the code below and there is basically no difference between the two now.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
var timeIt = function(){ var start, end, result, loopCount = 100000; // Using Implicit Conversion start = new Date().getTime(); for(var i=0;i<loopCount;i++){ for(var key in truthy){ result = (truthy[key] === true); } } end = new Date().getTime(); console.log((end - start)/1000.00 + "seconds for implicit conversion"); // Using !! Conversion start = new Date().getTime(); for(var i=0;i<loopCount;i++){ for(var key in truthy){ result = (!!truthy[key] === true); } } end = new Date().getTime(); console.log((end - start)/1000.00 + "seconds for inverse falsey conversion"); } timeIt(); timeIt(); timeIt(); |
If you want to see this for yourself, check out the Plunker below – again, you’ll want to have developer tools enabled in your browser of choice and inspect the console output. Older browsers *PROBABLY* won’t work! 🙂 Note that the page will take a little bit of time to load due to the looping occurring in the code above. Give it a little time…the results are worth a peek. Also, someone give it a shot in IE – I’m curious as to how it handles itself.
http://plnkr.co/edit/cvCda9uX6bW4CHAnxlT1?p=preview
Wrapping Up
I’m actually going to be re-evaluating whether you should ever need to use !!. As my tests above indicated (after some feedback both in the comments below and on Reddit), there’s no performance benefit from using !!. It’s only doing an explicit cast from some variable to a negated boolean and then inverting it back to the original boolean representation of the variable value. From the output from the first plunker using the console logs, I saw absolutely no difference between the statement:
1 2 3 |
if(someVar){ doSomething... } |
versus
1 2 3 |
if(!!someVar){ doSomething... } |
I’ll be updating later as I run some more tests this evening, but for the time being, I can’t see a need for using !!.
In the meantime, check out this fantastic reference provided via sigwhite on Reddit – an idiomatic guide to JavaScript coding: