Why does !!1=="1" equal true and !!2=="2" equal false?
JavascriptJavascript Problem Overview
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?
Javascript Solutions
Solution 1 - Javascript
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
.
Solution 2 - Javascript
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
Solution 3 - Javascript
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
Solution 4 - Javascript
!!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.
Solution 5 - Javascript
Because "1" may be considered as "true" when you do equality check, not identity, but "2" - can't.