What is the !! (not not) operator in JavaScript?
I saw some code that seems to use an operator I don't recognize, in the form of two exclamation points, like so: !!
. Can someone please tell me what this operator does?
The context in which I saw this was,
this.vertical = vertical !== undefined ? !!vertical : this.vertical;
Solution 1:
Converts Object
to boolean
. If it was falsey (e.g. 0
, null
, undefined
, etc.), it will be false
, otherwise, true
.
!oObject // inverted boolean
!!oObject // non inverted boolean so true boolean representation
So !!
is not an operator, it's just the !
operator twice.
Real World Example "Test IE version":
const isIE8 = !! navigator.userAgent.match(/MSIE 8.0/);
console.log(isIE8); // returns true or false
If you ⇒
console.log(navigator.userAgent.match(/MSIE 8.0/));
// returns either an Array or null
But if you ⇒
console.log(!!navigator.userAgent.match(/MSIE 8.0/));
// returns either true or false
Solution 2:
It's a horribly obscure way to do a type conversion.
!
is NOT. So !true
is false
, and !false
is true
. !0
is true
, and !1
is false
.
So you're converting a value to a boolean, then inverting it, then inverting it again.
// Maximum Obscurity:
val.enabled = !!userId;
// Partial Obscurity:
val.enabled = (userId != 0) ? true : false;
// And finally, much easier to understand:
val.enabled = (userId != 0);
Solution 3:
!!expr
(two !
operators followed by an expression) returns a Boolean value (true
or false
) depending on the truthiness of the expression. It makes more sense when used on non-boolean types. Consider these examples, especially the 3rd example and onward:
!!false === false
!!true === true
!!0 === false
!!parseInt("foo") === false // NaN is falsy
!!1 === true
!!-1 === true // -1 is truthy
!!(1/0) === true // Infinity is truthy
!!"" === false // empty string is falsy
!!"foo" === true // non-empty string is truthy
!!"false" === true // ...even if it contains a falsy value
!!window.foo === false // undefined value is falsy
!!undefined === false // undefined primitive is falsy
!!null === false // null is falsy
!!{} === true // an (empty) object is truthy
!![] === true // an (empty) array is truthy; PHP programmers beware!
Solution 4:
Brew some tea:
!!
is not an operator. It is the double-use of !
-- which is the logical "not" operator.
In theory:
!
determines the "truth" of what a value is not:
-
The truth is that
false
is nottrue
(that's why!false
results intrue
) -
The truth is that
true
is notfalse
(that's why!true
results infalse
)
!!
determines the "truth" of what a value is not not:
-
The truth is that
true
is not nottrue
(that's why!!true
results intrue
) -
The truth is that
false
is not notfalse
(that's why!!false
results infalse
)
What we wish to determine in the comparison is the "truth" about the value of a reference, not the value of the reference itself. There is a use-case where we might want to know the truth about a value, even if we expect the value to be false
(or falsey), or if we expect the value not to be typeof boolean
.
In practice:
Consider a concise function which detects feature functionality (and in this case, platform compatibility) by way of dynamic typing (aka "duck typing"). We want to write a function that returns true
if a user's browser supports the HTML5 <audio>
element, but we don't want the function to throw an error if <audio>
is undefined; and we don't want to use try ... catch
to handle any possible errors (because they're gross); and also we don't want to use a check inside the function that won't consistently reveal the truth about the feature (for example, document.createElement('audio')
will still create an element called <audio>
even if HTML5 <audio>
is not supported).
Here are the three approaches:
// this won't tell us anything about HTML5 `<audio>` as a feature
var foo = function(tag, atr) { return document.createElement(tag)[atr]; }
// this won't return true if the feature is detected (although it works just fine)
var bar = function(tag, atr) { return !document.createElement(tag)[atr]; }
// this is the concise, feature-detecting solution we want
var baz = function(tag, atr) { return !!document.createElement(tag)[atr]; }
foo('audio', 'preload'); // returns "auto"
bar('audio', 'preload'); // returns false
baz('audio', 'preload'); // returns true
Each function accepts an argument for a <tag>
and an attribute
to look for, but they each return different values based on what the comparisons determine.
But wait, there's more!
Some of you probably noticed that in this specific example, one could simply check for a property using the slightly more performant means of checking if the object in question has a property. There are two ways to do this:
// the native `hasOwnProperty` method
var qux = function(tag, atr) { return document.createElement(tag).hasOwnProperty(atr); }
// the `in` operator
var quux = function(tag, atr) { return atr in document.createElement(tag); }
qux('audio', 'preload'); // returns true
quux('audio', 'preload'); // returns true
We digress...
However rare these situations may be, there may exist a few scenarios where the most concise, most performant, and thus most preferred means of getting true
from a non-boolean, possibly undefined value is indeed by using !!
. Hopefully this ridiculously clears it up.
Solution 5:
!!
converts the value to the right of it to its equivalent boolean value. (Think poor man's way of "type-casting"). Its intent is usually to convey to the reader that the code does not care what value is in the variable, but what it's "truth" value is.