Цитата:
При сравнении значений разных типов JavaScript приводит каждое из них к числу.
Откуда дровишки? Правда о JavaScript написана только в одном месте - в документации языка. Поэтому смотрим доку:
https://262.ecma-international.org/16.0/index.htmlEqualityExpression : EqualityExpression == RelationalExpression
1. Let lRef be ? Evaluation of EqualityExpression.
2. Let lVal be ? GetValue(lRef).
3. Let rRef be ? Evaluation of RelationalExpression.
4. Let rVal be ? GetValue(rRef).
5. Return ? IsLooselyEqual(rVal, lVal).
Ага, значит, ищем IsLooselyEqual:
The abstract operation IsLooselyEqual takes arguments x (an ECMAScript language value) and y (an ECMAScript language value) and returns either a normal completion containing a Boolean or a throw completion. It provides the semantics for the == operator. It performs the following steps when called:
1. If SameType(x, y) is true, then
a. Return IsStrictlyEqual(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.6.2.
5. If x is a Number and y is a String, return ! IsLooselyEqual(x, ! ToNumber(y)).
6. If x is a String and y is a Number, return ! IsLooselyEqual(! ToNumber(x), y).
7. If x is a BigInt and y is a String, then
a. Let n be StringToBigInt(y).
b. If n is undefined, return false.
c. Return ! IsLooselyEqual(x, n).
8. If x is a String and y is a BigInt, return ! IsLooselyEqual(y, x).
9. If x is a Boolean, return ! IsLooselyEqual(! ToNumber(x), y).
10. If y is a Boolean, return ! IsLooselyEqual(x, ! ToNumber(y)).
11. If x is either a String, a Number, a BigInt, or a Symbol and y is an Object, return ! IsLooselyEqual(x, ? ToPrimitive(y)).
12. If x is an Object and y is either a String, a Number, a BigInt, or a Symbol, return ! IsLooselyEqual(? ToPrimitive(x), y).
13. If x is a BigInt and y is a Number, or if x is a Number and y is a BigInt, then
a. If x is not finite or y is not finite, return false.
b. If ℝ(x) = ℝ(y), return true; otherwise return false.
14. Return false.
Вот и весь ответ. В JS есть чёткий алгоритм нестрогого сравнения, который назван IsLooselyEqual, а всё остальное - отсебятина.
null == undefined; // вернёт true
В Javascript при нестрогом сравнении null равен undefined не потому, что они оба привелись к 0, а потому что в пункте 2 чётко сказано, если первый оператор null и второй оператор undefined, то нужно вернуть true.