66

As the title states, why does:

> !!1=="1"

equal

True

and

> !!2=="2"

equal:

False

Likewise, why does > "1"==true equal true and > "2"==true equal false

I'm baffled. Are these just bugs in JS or what's going on here?

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
Michael Rader
  • 5,839
  • 8
  • 33
  • 43
  • 3
    @Michael: 2==“2” equal false for you? For me it's working correctly http://jsfiddle.net/HGEcs/ – Ishan Jain May 16 '14 at 05:24
  • 8
    This is why you should ALWAYS be using `===` for comparison in JavaScript. – tester May 16 '14 at 05:25
  • 1
    Is the javascript bang like the C bang? If so, then `!!1` and `!!2` both equal 1. – jthill May 16 '14 at 05:25
  • 1
    yes its a "bug" and highly discouraged. it is very confusing. == does type coercion see http://bonsaiden.github.io/JavaScript-Garden/#types for more details. and read Javscript: The Good Parts book – StephenNYC May 16 '14 at 05:27
  • 54
    No, it's not a bug. You simply should not compare booleans to strings if you don't know what it means. – Bergi May 16 '14 at 05:50
  • 12
    Depends what you mean by "bug". In the usual sense of the word, no, this isn't a bug - but it *is* a design flaw. – Harry Johnston May 16 '14 at 06:15
  • 1
    You could have easily figured that out by yourself by adding parantheses to figure out which operator takes precedence. – Niklas B. May 16 '14 at 13:05
  • 2
    Please notice that these aren't duplicates. We here are considering the case **compare boolean to numeric string**, not something similar. – Bergi May 16 '14 at 15:42
  • 1
    @HarryJohnston I'd say it's not a design _flaw_ but an example of a design convenience (being able to use `123=="123"`) that can be misused, either by design or accident. – TripeHound May 16 '14 at 15:49
  • @Bergi you marked this as a duplicate, why? It's not the same question. This question is much more clear and what would be searched if someone were looking for the answer. – Michael Rader May 16 '14 at 16:39
  • 2
    @MichaelRader: No, I did not (see my previous comment about why it's not a dupe). In fact, [I just reopened it](http://stackoverflow.com/posts/23693089/revisions) with my Gold Badge priviledges :-) – Bergi May 16 '14 at 16:49
  • @Bergi great, I appreciate it. I Google this exact questions with no answers found, so i think it will be searched similarly by others. – Michael Rader May 16 '14 at 16:53
  • Though I'm very much of the opinion that weak dynamic type systems are a bad idea, I don't know what you find so strange about this particular example. You also wouldn't be surprised to see that `1 * 1 == 1` yet `2 * 2 ≠ 2`, would you? You have in mind that `!` should be self-inverse and hence `!!` never do anything, but this is obviosly only true if you restrict yourself to proper boolean values (which is a no-brainer in a proper strong static type system). – leftaroundabout May 17 '14 at 11:45
  • @Bergi I don't understand why this question keeps getting closed. Can you reopen it again?? – Michael Rader May 19 '14 at 20:41

5 Answers5

207

As per the Operator precedence rules, logical ! has higher priority over ==. So, in both the cases, !! is evaluated first.

Note: Truthiness of various objects have been explained in this answer of mine.

First Case

!!1 == "1"

!1 will be evaluated to false, since 1 is considered Truthy. Negating again we get true. So the expression becomes

true == "1"

Now, the coercion rules kick in as you have used == operator, which evaluates as per the The Abstract Equality Comparison Algorithm defined in ECMAScript 5.1 Specification,

6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.

So, true will be converted to a number, which is 1 as per ToNumber algorithm for Boolean values. Now the expression becomes

1 == "1"

Now,

4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).

So, "1" will be converted to a number and that will give 1, as per the ToNumber algorithm. That is why it shows true in the first case.

Second Case

The same rules are applied here.

!!2 == "2"

becomes

true == "2"

then

1 == "2"

which becomes

1 == 2

which is not true, that is why the second case prints false.

Community
  • 1
  • 1
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 7
    +1 No wonder: `100==true` is always false. This lingered some Confusion as in; How can both `Negative Numbers` and `Positive Number` `== true` be `false` except 1 which is a Positive number?... Your Explanation really shades some GreatLight on this issue. mostly the point **4.** – ErickBest May 16 '14 at 05:50
  • @MichaelRader Nope :-) It is the intended behavior, as per the specifications. – thefourtheye May 16 '14 at 05:54
  • 5
    @MichaelRader If you want to compare the values then you might want to use `===` operator, which uses [Strict Equality Algorithm](http://es5.github.io/#x11.9.6) – thefourtheye May 16 '14 at 05:55
  • It uses this Logic: **Number:** *The result is false if the argument is* `+0`, `−0`, or `NaN;` otherwise the result is `true`. See: http://es5.github.io/#x9.2 – ErickBest May 16 '14 at 05:56
  • @thefourtheye very interesting, considering the book I'm going through calls them "bugs rather than features." Had a feeling there had to be some logic behind it. And yes, I would always use `===`. – Michael Rader May 16 '14 at 05:57
  • 4
    @MichaelRader Sure, but please go through the documentation to know the limitations of `===` before diving in ;-) – thefourtheye May 16 '14 at 05:58
  • @ErickBest You are correct, any other number is considered Truthy :) – thefourtheye May 16 '14 at 05:58
  • I'm not new, lol, I know the limitations. I'm just trying to get a better grasp of the inner workings. – Michael Rader May 16 '14 at 05:59
  • 4
    I love when people give step-by-step breakdowns of code, because not all of us know what goes on in the background. Thanks! – Chris Cirefice May 16 '14 at 17:20
  • 1
    If you're trying to create a statement out of this, you might opt for a little boolean algebra, so if you have `var1 = 2` and `var2 = 2`, then you can use `if !!var1 and var2`, since you're not checking for the integer value of these numbers, but instead want their boolean value. – jfa May 16 '14 at 23:07
  • 1
    Better use `===` for value comparison and I do love the answer `Yes, this is javascript` – stanleyxu2005 May 17 '14 at 07:26
13

tldr; this is due to the [ToNumber] conversions in the == operator algorithm.

The first step is to simplify the expression. Since !!x=="x" is parsed like (!!x)=="x" and !!a_truthy_expression -> true, the actual relevant expression for the equality is

!!1=="2" -> true=="1" -> Boolean==String
!!2=="2" -> true=="2" -> Boolean==String

So then looking at the rules for 11.9.3 The Abstract Equality Comparison Algorithm and following along with the application yields

Rule 6 - If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.

which results in Number==String or 1=="1" and 1=="2", respectively1. Then the rule

Rule 7 - If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).

is applied which results in Number==Number or 1==1 and 1==2, respectively1; the latter is clearly false.

Rule 1 - If Type(x) is the same as Type(y), then [by c.iii.] If x is the same Number value as y, return true [else return false].

(The same algorithm explains the String==Boolean case when the complementing rules are applied.)


1To see the [ToNumber] rule applied, consider:

+false -> 0
+true  -> 1
+"1"   -> 1
+"2"   -> 2
user2864740
  • 60,010
  • 15
  • 145
  • 220
5

Its a precedence operator problem.

The ! operator is an unary operator. That means the left side must be an expression or a boolean evaluable section. See Javascript MDN.

!!1==1 is not necessary !!(1==1)
!!2==2 is not necessary !!(2==2)

I think that these expressions should be consistent if the equal operator has more precedence than ! operator. But if we consider the opposite, evaluating first negations we have:

!!1 == 1
!1 -> false
!!1 -> true
!!1 == 1 

And with the two

!!2==2
!2 -> false
!!2 -> true
(!!2) == 2 -> false

That is because the ! operator has precedence over == operator

See Mozilla Operator Preference

1

!!1 is equal to true, and "1" is equal to true ("0" is false, so is every other string). So !!1 == "1" evaluates to true == true, which of course returns true.

!!2 is also equal to true. As I mentioned earlier, "2" is not "1", so it's false. Therefore, we have true == false, which of course returns false.

If you want to see if 2 (a number) is equal to "2" (a string representation of a number), then all you have to do is 2 == "2", which evaluates to 2 == 2, which is true. The difference is that we're not comparing a boolean against a boolean. We're comparing a number against a number.

Basically, putting !! in front of a number converts to a boolean, which forces JavaScript to cast your string to a boolean instead of a number.

user2864740
  • 60,010
  • 15
  • 145
  • 220
Meredith
  • 844
  • 6
  • 17
  • Which is exactly what I said. – Meredith May 16 '14 at 05:31
  • YOU SAID: *As I mentioned earlier, "2" is not "1".* Did he say `2 == 1` ??... try to explain that point – ErickBest May 16 '14 at 05:34
  • I said that "1" is the only string that is equal to true. Therefore, "2" is equal to false, which gives the expression `true == false`, hence why `!!2 == "2"` is false. – Meredith May 16 '14 at 05:35
  • 7
    -1. The strings are not being casted to booleans. The booleans are casted to numbers. Also, "*"0" is false*" is confusing (if not wrong), because `"0"` is truthy: `!!"0" === true` and `"0" == false` – Bergi May 16 '14 at 05:48
  • 4
    -1. `!!"" === false`, `!!anyOtherString === true`. In other words the empty string is falsey, all other strings are truthy. Your first sentence directly contradicts this – erm410 May 16 '14 at 12:44
-1

Because "1" may be considered as "true" when you do equality check, not identity, but "2" - can't.

Miraage
  • 3,334
  • 3
  • 26
  • 43