Why is null in JavaScript bigger than -1, less than 1, but not equal (==) to 0? What is it exactly then?

When you compare null for equality to 0, the result is false. If you force null to be interpreted in a numeric context then it is treated like 0 and the result becomes true.

You can force it to be numeric by putting + in front, or by using numeric operators like <, <=, >, and >=. Notice how null >= 0 and null <= 0 are both true.

> null == 0
false
> +null == 0
true
> null >= 0
true
> null <= 0
true

The ECMAScript Language Specification defines when a so-called "ToNumber" conversion is performed. When it is, null and false are both converted to 0.

§9.1 Type Conversion and Testing:

Table 14 — To Number Conversions

Argument Type     Result
-------------     ------
Undefined         Return NaN
Null              Return +0
Boolean           Return 1 if argument is true. Return +0 if argument is false.
Number            Return argument (no conversion).
String            See grammar and note below.

Knowing when the ToNumber conversion is applied depends on the operator in question. For the relational operators <, <=, >, and >= see:

§11.8.5 The Abstract Relational Comparison Algorithm:

The comparison x < y, where x and y are values, produces true, false, or undefined (which indicates that at least one operand is NaN). Such a comparison is performed as follows:

  1. Call ToPrimitive(x, hint Number).

  2. Call ToPrimitive(y, hint Number).

  3. If Type(Result(1)) is String and Type(Result(2)) is String, go to step 16. (Note that this step differs from step 7 in the algorithm for the addition operator + in using and instead of or.)

  4. Call ToNumber(Result(1)).

  5. Call ToNumber(Result(2)).

The == operator is different. Its type conversions are described below. Notice how null and false follow different rules.

§11.9.3 The Abstract Equality Comparison Algorithm

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 different from Type(y), go to step 14.

...

14. If x is null and y is undefined, return true.

15. If x is undefined and y is null, return true.

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

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

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

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

20. If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).

21. If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

22. Return false.

If you read carefully you can see why false == 0 is true but null == 0 is false.

  • For false == 0, Type(x) is Boolean. This means Step 18's type conversion is applied, and false is converted to a number. ToNumber(false) is 0, and 0 == 0 is true, so the comparison succeeds.

  • For null == 0, Type(x) is Null. None of the type checks match so the comparison falls through to Step 22, which returns false. The comparison fails.


null casts to 0 as a number: (+null) is 0. > and < cast null to this value, so when compared to numbers it acts as zero. == doesn't cast null to a number, so null == 0 is false.