In the first two examples, since the comparison involves a primitive value of b
, a
and c
end up being coerced to primitives. In the last case, on the other hand, you are comparing two distinct objects, and therefore no coercion takes place.
To be precise, the double-equal comparison with a boolean uses this rule from the spec (taking the case of b == c
):
If Type(x)
is Boolean
, return the result of the comparison ToNumber(x) == y
.
So this means that ToNumber(b)
is compared with c
. ToNumber(b)
is 1. So we are comparing 1
with c
. Next, the following rule is applied:
If Type(x)
is either String
or Number
and Type(y)
is Object
,
return the result of the comparison x == ToPrimitive(y)
.
So this means we compare 1
with ToPrimitive(c)
which is ToPrimitive(Boolean(true))
. ToPrimitive
invokes valueOf
, which yields 1
. So we compare 1
to 1
. QED.
In the case of your third example, the following portion of the spec applies:
If Type(x)
is the same as Type(y)
, then...Return true if x
and y
refer to the same object. Otherwise, return false.
To answer your question:
Mathematically, how can we explain this contradiction ?
It's not a matter of mathematics. It's a matter of the definition of comparisons in the JS spec.