javascriptnullcomparisonequality

Why `null >= 0 && null <= 0` but not `null == 0`?


I had to write a routine that increments the value of a variable by 1 if its type is number and assigns 0 to the variable if not, where the variable is initially null or undefined.

The first implementation was v >= 0 ? v += 1 : v = 0 because I thought anything not a number would make an arithmetic expression false, but it was wrong since null >= 0 is evaluated to true. Then I learned null behaves like 0 and the following expressions are all evaluated to true.

Of course, null is not 0. null == 0 is evaluated to false. This makes the seemingly tautological expression (v >= 0 && v <= 0) === (v == 0) false.

Why is null like 0, although it is not actually 0?


Solution

  • Your real question seem to be:

    Why:

    null >= 0; // true
    

    But:

    null == 0; // false
    

    What really happens is that the Greater-than-or-equal Operator (>=), performs type coercion (ToPrimitive), with a hint type of Number, actually all the relational operators have this behavior.

    null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:

    null == null; // true
    null == undefined; // true
    

    Values false, '0', and [] are subject to numeric coercion to zero. Strings coerce to zero when, after trimming whitespace, the result is the empty string ("").

    You can see the inner details of this process in the The Abstract Equality Comparison Algorithm and The Abstract Relational Comparison Algorithm.

    In Summary:

    This also explains how Date objects can be compared numerically.

    As for null >= 0, as ToPrimitive(null, hint: Number) results null.

    Null The result equals the input argument (no conversion).

    For the "The Abstract Relational Comparison Algorithm" of EcmaScript 5.1, this occurs in step 3.

    EcmaScript 2025, 7.2.12 IsLessThan ( x, y, LeftFirst ), step 4 the same effect. (see: https://tc39.es/ecma262/#sec-islessthan)

    c. NOTE: Because px and py are primitive values, evaluation order is not important. d. Let nx be ? ToNumeric(px). e. Let ny be ? ToNumeric(py).

    7.1.4 ToNumber ( argument ) The abstract operation ToNumber takes argument argument (an ECMAScript language value) and returns either a normal completion containing a Number or a throw completion. It converts argument to a value of type Number. It performs the following steps when called: [[ToPrimitive]], EcmaScript 5.1

    1. If argument is a Number, return argument.
    2. If argument is either a Symbol or a BigInt, throw a TypeError exception.
    3. If argument is undefined, return NaN.
    4. If argument is either null or false, return +0𝔽.
    5. If argument is true, return 1𝔽.
    6. If argument is a String, return StringToNumber(argument).
    7. Assert: argument is an Object.
    8. Let primValue be ? ToPrimitive(argument, NUMBER).
    9. Assert: primValue is not an Object.
    10. Return ? ToNumber(primValue).