As the title states, why does:
> !!1==\"1\"
equal
True
and
> !!2==\"2\"
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
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.
!!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)isBoolean, return the result of the comparisonToNumber(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)isNumberandType(y)isString, return the result of the comparisonx == 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.
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.
!!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.
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
Because "1" may be considered as "true" when you do equality check, not identity, but "2" - can't.