skip to content

In JavaScript, null == undefined is true, but null == 0 and null == false are both false. Which rule of the loose-equality algorithm explains this?

level: middleimportance: should knowfreq 52%

answer

  1. a rule of its own, early in the algorithm
  2. these two are never converted
  3. equal to each other, to nothing else
  4. Number(null) is zero, the comparison still is not

basics

~20 s

The loose-equality algorithm has an explicit step making null and undefined equal to each other and to nothing else. Neither value is ever converted to a number, so null == 0 and null == false both fall through to false.

solid answer

~50 s

Loose equality contains a dedicated step for these two values: if one operand is `null` and the other is `undefined`, the result is `true` — and there is no rule anywhere that converts `null` or `undefined` to a number, a string, or a boolean. So `null == undefined` and `null == null` are true, while `null == 0`, `null == false`, `null == ''` and `undefined == 0` all fall through to the final "otherwise return false" step. This is the one piece of loose equality worth exploiting: `x == null` is a compact, exact test for "x is null or undefined", equivalent to `x === null || x === undefined` and matching nothing else. It is also why loose equality is not a general falsiness test — `null` is falsy, yet it is loosely equal to no other falsy value.

code

javascript · 7 lines
javascript
console.log(null == undefined); // true
console.log(null == null);      // true
console.log(null == 0);         // false
console.log(null == false);     // false
console.log(null == '');        // false
console.log(undefined == 0);    // false
console.log(Number(null));      // 0 - explicit conversion disagrees

go deeper

for a junior

Remember that null == undefined is true and that null == 0 is false, and that writing x == null is a normal way to check for a missing value.

for a middle

Explain the mechanism: an explicit algorithm step pairs null with undefined, and no rule ever converts either one, so everything else falls through to false. Note that Number(null) being 0 is a separate conversion.

for a senior

Show the judgment call about which absent value you mean — an exact nullish check that preserves 0 and '' versus a falsiness check that discards them — and name the data-loss bug the wrong choice causes.

for a principal

Own the modelling question behind the trivia: decide whether a field may hold both absent values at all, and normalise absence to a single representation at the parsing boundary so downstream code never has to choose between the two checks.

## The rule, stated exactly The abstract equality comparison checks, right after the same-type shortcut, whether one operand is `null` and the other is `undefined`. If so the answer is `true`. Nothing later in the algorithm ever converts `null` or `undefined` into another type — there is no "ToNumber(null)" branch in the comparison. That is the whole explanation, and it produces a clean, memorable result: **`null` and `undefined` are loosely equal to each other and to nothing else in the language.** ```js console.log(null == undefined); // true - the special rule console.log(null == null); // true - same type, strict console.log(undefined == undefined); // true console.log(null == 0); // false console.log(null == false); // false console.log(null == ''); // false console.log(null == NaN); // false console.log(undefined == 0); // false ``` (One host-provided legacy object in browsers, `document.all`, is deliberately specified to compare loosely equal to `null` and `undefined` as a web-compatibility quirk. It is trivia, not a rule you can build on.) ## Why people expect otherwise The usual wrong prediction is `null == 0` being true, and it comes from mixing up two different conversions. `Number(null)` really is `0` — explicit numeric conversion of `null` produces zero, which is why `null + 1` is `1`. But the loose-equality algorithm never performs that conversion; it short-circuits on the null/undefined step and then runs out of applicable rules. So explicit conversion and implicit comparison genuinely disagree here, and the candidate who says "but `Number(null)` is 0" is right about the conversion and wrong about the comparison. The same trap appears with relational operators, which use a *different* algorithm that does convert: `null >= 0` is `true` and `null > 0` is `false`, while `null == 0` is `false`. So `null` is simultaneously "not equal to 0" and "greater than or equal to 0". This is a good illustration that `==` is its own algorithm rather than a general coercion policy applied everywhere. ## null is falsy, but that is a separate system `null` and `undefined` are both falsy, and so are `0`, `''`, `NaN` and `false`. It is tempting to conclude that falsy values are loosely equal to one another. They are not. Falsiness is decided by a boolean conversion used in `if` and `!`; loose equality is decided by the algorithm above. The two overlap in some cases (`'' == 0` is true) and diverge sharply in others (`null == 0` is false; `'0' == false` is true even though `'0'` is truthy). Treat them as unrelated mechanisms that happen to share some inputs. ## The one useful idiom Because the rule is exact, `x == null` is a precise test for "x is null or undefined" and nothing else: ```js function has(value) { return value != null; // false only for null and undefined } console.log(has(0)); // true - zero is a real value console.log(has('')); // true - empty string is a real value console.log(has(NaN)); // true console.log(has(null)); // false console.log(has(undefined)); // false ``` This is the check you want when a parameter is optional and `0`, `''` or `false` are legitimate values — a quantity, a search term, a toggle. Writing `if (!value)` there is the classic bug: it rejects `0` and `''` along with the genuinely-missing cases. ## Distinguishing the two absent values when you must `x == null` deliberately blurs `null` and `undefined`. Sometimes that distinction matters: `undefined` typically means "never set / property absent / argument omitted", while `null` usually means "explicitly set to nothing", and some data sources use them differently. When the difference is meaningful, test strictly — `x === undefined` or `x === null` — and be explicit in the code about which case you are handling. A default parameter value, for example, is applied only for `undefined`, never for `null`, so a function that receives `null` will not get its default. ## What to say in the interview State the rule first: there is an explicit step for null-versus-undefined, and neither value is ever coerced. Then give the two consequences — `null == 0` is false despite `Number(null)` being `0`, and `x == null` is an exact nullish check. If you have room, mention that relational comparison uses a different algorithm and does convert, so `null >= 0` is true. That trio shows you are reading the algorithm rather than reciting habits.

  • Number(null) is 0, so why doesn't null == 0 follow from that?
    Because loose equality never calls ToNumber on `null`. The algorithm hits its null/undefined step, finds the other operand is a number rather than `undefined`, and falls through to the final `false`. Explicit conversion and the comparison algorithm are separate mechanisms — `null + 1` really is `1`, and `null == 0` really is `false`.
  • When would you deliberately test x === undefined instead of x == null?
    When the distinction carries meaning — for example when `undefined` means "the property was never present" and `null` means "explicitly cleared", which some APIs and stored documents rely on. Default parameter values also apply only for `undefined`, so a function passed `null` skips its default. If both absent-ish cases should behave the same, `x == null` is the clearer check.
  • Why is if (!value) a poor substitute for if (value == null)?
    `!value` is a falsiness test, so it also fires for `0`, `''`, `NaN`, `-0`, `0n` and `false`. If any of those is a legitimate value — a count of zero, a cleared search box, a switched-off toggle — the check misclassifies real data as missing. `value == null` matches exactly the two absent values and leaves everything else alone.

saying these in an interview costs you the question

  • null == 0 is true because Number(null) is 0
  • null is loosely equal to every falsy value
  • null == undefined is false because their types differ
  • undefined == '' is true since both are empty
  • == null and !value are interchangeable checks

context