What is the !! (not not) operator in JavaScript?

2018-12-30 22:58发布

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;

30条回答
美炸的是我
2楼-- · 2018-12-30 23:32

! is "boolean not", which essentially typecasts the value of "enable" to its boolean opposite. The second ! flips this value. So, !!enable means "not not enable," giving you the value of enable as a boolean.

查看更多
冷夜・残月
3楼-- · 2018-12-30 23:34

It seems that the !! operator results in a double negation.

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true
查看更多
爱死公子算了
4楼-- · 2018-12-30 23:35

I think worth mentioning is, that a condition combined with logical AND/OR will not return a boolean value but last success or first fail in case of && and first success or last fail in case of || of condition chain.

res = (1 && 2); // res is 2
res = (true && alert) // res is function alert()
res = ('foo' || alert) // res is 'foo'

In order to cast the condition to a true boolean literal we can use the double negation:

res = !!(1 && 2); // res is true
res = !!(true && alert) // res is true
res = !!('foo' || alert) // res is true
查看更多
心情的温度
5楼-- · 2018-12-30 23:35

After seeing all these great answers, I would like to add another reason for using !!. Currenty I'm working in Angular 2-4 (TypeScript) and I want to return a boolean as false when my user is not authenticated. If he isn't authenticated, the token-string would be null or "". I can do this by using the next block of code:

public isAuthenticated(): boolean {
   return !!this.getToken();
}
查看更多
萌妹纸的霸气范
6楼-- · 2018-12-30 23:36

I suspect this is a leftover from C++ where people override the ! operator but not the bool operator.

So to get a negative(or positive) answer in that case you would first need to use the ! operator to get a boolean, but if you wanted to check the positive case would use !!.

查看更多
高级女魔头
7楼-- · 2018-12-30 23:38

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:

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}

Keep in mind that this is a JSX convention, not one inherent to JavaScript.

But if you see strange 0s in your rendered JSX, think loose falsy management.

查看更多
登录 后发表回答