So many answers doing half the work. Yes, !!X
could be read as "the truthiness of X [represented as a boolean]". But !!
isn't, practically speaking, so important for figuring out whether a single variable is (or even if many variables are) truthy or falsy. !!myVar === true
is the same as just myVar
. Comparing !!X
to a "real" boolean isn't really useful.
What you gain with !!
is the ability to check the truthiness of multiple variables against each other in a repeatable, standardized (and JSLint friendly) fashion.
Simply casting :(
That is...
0 === false
is false
.
!!0 === false
is true
.
The above's not so useful. if (!0)
gives you the same results as if (!!0 === false)
. I can't think of a good case for casting a variable to boolean and then comparing to a "true" boolean.
See "== and !=" from JSLint's directions (note: Crockford is moving his site around a bit; that link is liable to die at some point) for a little on why:
The == and != operators do type coercion before comparing. This is bad because it causes ' \t\r\n' == 0 to be true. This can mask type errors. JSLint cannot reliably determine if == is being used correctly, so it is best to not use == and != at all and to always use the more reliable === and !== operators instead.
If you only care that a value is truthy or falsy, then use the short form. Instead of
(foo != 0)
just say
(foo)
and instead of
(foo == 0)
say
(!foo)
Note that there are some unintuitive cases where a boolean will be cast to a number (true
is cast to 1
and false
to 0
) when comparing a boolean to a number. In this case, !!
might be mentally useful. Though, again, these are cases where you're comparing a non-boolean to a hard-typed boolean, which is, imo, a serious mistake. if (-1)
is still the way to go here.
╔═══════════════════════════════════════╦═══════════════════╦═══════════╗
║ Original ║ Equivalent ║ Result ║
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (-1 == true) console.log("spam") ║ if (-1 == 1) ║ undefined ║
║ if (-1 == false) console.log("spam") ║ if (-1 == 0) ║ undefined ║
║ Order doesn't matter... ║ ║ ║
║ if (true == -1) console.log("spam") ║ if (1 == -1) ║ undefined ║
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (!!-1 == true) console.log("spam") ║ if (true == true) ║ spam ║ better
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
║ if (-1) console.log("spam") ║ if (truthy) ║ spam ║ still best
╚═══════════════════════════════════════╩═══════════════════╩═══════════╝
And things get even crazier depending on your engine. WScript, for instance, wins the prize.
function test()
{
return (1 === 1);
}
WScript.echo(test());
Because of some historical Windows jive, that'll output -1 in a message box! Try it in a cmd.exe prompt and see! But WScript.echo(-1 == test())
still gives you 0, or WScript's false
. Look away. It's hideous.
Comparing truthiness :)
But what if I have two values I need to check for equal truthi/falsi-ness?
Pretend we have myVar1 = 0;
and myVar2 = undefined;
.
myVar1 === myVar2
is 0 === undefined
and is obviously false.
!!myVar1 === !!myVar2
is !!0 === !!undefined
and is true! Same truthiness! (In this case, both "have a truthiness of falsy".)
So the only place you'd really need to use "boolean-cast variables" would be if you had a situation where you're checking if both variables have the same truthiness, right? That is, use !!
if you need to see if two vars are both truthy or both falsy (or not), that is, of equal (or not) truthiness.
I can't think of a great, non-contrived use case for that offhand. Maybe you have "linked" fields in a form?
if (!!customerInput.spouseName !== !!customerInput.spouseAge ) {
errorObjects.spouse = "Please either enter a valid name AND age "
+ "for your spouse or leave all spouse fields blank.";
}
So now if you have a truthy for both or a falsy for both spouse name and age, you can continue. Otherwise you've only got one field with a value (or a very early arranged marriage) and need to create an extra error on your errorObjects
collection.
EDIT 24 Oct 2017, 6 Feb 19:
3rd party libraries that expect explicit Boolean values
Here's an interesting case... !!
might be useful when 3rd party libs expect explicit Boolean values.
For instance, False in JSX (React) has a special meaning that's not triggered on simple falsiness. If you tried returning something like the following in your JSX, expecting an int in messageCount
...
{messageCount && <div>You have messages!</div>}
... you might be surprised to see React render a 0
when you have zero messages. You have to explicitly return false for JSX not to render. The above statement returns 0
, which JSX happily renders, as it should. It can't tell you didn't have Count: {messageCount && <div>Get your count to zero!</div>}
(or something less contrived).
One fix involves the bangbang, which coerces 0
into !!0
, which is false
:
{!!messageCount && <div>You have messages!</div>}
JSX' docs suggest you be more explicit, write self-commenting code, and use a comparison to force to a Boolean.
{messageCount > 0 && <div>You have messages!</div>}
I'm more comfortable handling falsiness myself with a ternary --
{messageCount ? <div>You have messages!</div> : false}
Same deal in Typescript: If you have a function that returns a boolean (or you're assigning a value to a boolean variable), you [usually] can't return/assign a boolean-y value; it has to be a strongly typed boolean. This means, iff myObject
is strongly typed, return !myObject;
works for a function returning a boolean, but return myObject;
doesn't. You have to return !!myObject
to match Typescript's expectations.
The exception for Typescript? If myObject
was an any
, you're back in JavaScript's Wild West and can return it without !!
, even if your return type is a boolean.
Keep in mind that these are JSX & Typescript conventions, not ones inherent to JavaScript.
But if you see strange 0
s in your rendered JSX, think loose falsy management.
if(vertical !== undefined) this.vertical = Boolean(vertical);
- it is much cleaner and clearer what is going on, requires no unnecessary assignment, is entirely standard, and is just as fast (on current FF and Chrome) jsperf.com/boolean-conversion-speed . – Phil H!!5/0
producesInfinity
rather thantrue
, as produced byBoolean(5/0)
.!!5/0
is equivalent to(!!5)/0
-- a.k.atrue/0
-- due to the!
operator having a higher precedence than the/
operator. If you wanted to Booleanize5/0
using a double-bang, you'd need to use!!(5/0)
. – matty