JavaScript truthiness in boolean to numbers comparison

This is because when either operand of an equality operator is a number, in nearly all cases the other operand is converted to a number and then the result is compared. So you're ending up comparing 1 (converted from true) with 2, not true with true. The only exceptions to that rule are null, undefined, and objects whose default value (see off-topic below) is null or undefined; comparing a number to those returns false (even though Number(null) is 0; don't ask).

Details in the specification, Section 11.9.3: "The Abstract Equality Comparison Algorithm". This was the text of that section as of ES 5.1, but that link is to the currently editor's draft (which is what each year's snapshot specification is based on) and there have been several :

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is the same as Type(y), then
    1. Return the result of performing Strict Equality Comparison x === y.
  2. If x is null and y is undefined, return true.
  3. If x is undefined and y is null, return true.
  4. NOTE: This step is replaced in section B.3.7.2.
  5. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ! ToNumber(y).
  6. If Type(x) is String and Type(y) is Number, return the result of the comparison ! ToNumber(x) == y.
  7. If Type(x) is BigInt and Type(y) is String, then
    1. Let n be ! StringToBigInt(y).
    2. If n is NaN, return false.
    3. Return the result of the comparison x == n.
  8. If Type(x) is String and Type(y) is BigInt, return the result of the comparison y == x.
  9. If Type(x) is Boolean, return the result of the comparison ! ToNumber(x) == y.
  10. If Type(y) is Boolean, return the result of the comparison x == ! ToNumber(y).
  11. If Type(x) is either String, Number, BigInt, or Symbol and Type(y) is Object, return the result of the comparison x == ? ToPrimitive(y).
  12. If Type(x) is Object and Type(y) is either String, Number, BigInt, or Symbol, return the result of the comparison ? ToPrimitive(x) == y.
  13. If Type(x) is BigInt and Type(y) is Number, or if Type(x) is Number and Type(y) is BigInt, then
    1. If x or y are any of NaN, +∞, or -∞, return false.
    2. If ℝ(x) = ℝ(y), return true; otherwise return false.
  14. Return false.

Note: The !s in the above are not negations, they indicate that the following abstract operation never results in an abrupt completion. Details in this article about reading the spec.

If you wanted to check that they were both truthy or both falsy, you could use the bang (!) or double-bang (!!) idiom to coerce them both to booleans:

var a = true,
    b = 2;
alert(a == b);     // "false", 1 !== 2
alert(!!a == !!b); // "true", true === true
alert(!a == !b);   // "true", false === false
a = false;
b = 0;
alert(a == b);     // "true", 0 === 0
alert(!!a == !!b); // "true", false === false
alert(!a == !b);   // "true", true === true

...but usually using == or != with booleans isn't ideal. But it does come up.

I tend to use the double-bang, but in JavaScript there's no reason to over the bang. (There's an argument for the double over the single in some other languages, though it's a weak one related to consistency with if (!!x). In JavaScript you never need the double-bang in the if (x) case, so...)


(Off-topic: The default value of most JavaScript objects is a string, though frequently one like "[object Object]" that ends up being NaN if you convert it to a number; but constructor functions can override that behavior via valueOf and toString. The default value of host objects is up to the host environment.)


The boolean true constant is promoted to a number, that being 1.