Day 3 · Concept 08
The === rule
=== compares without coercion: same type, same value. == coerces — and produces surprises. The rule is simple: always ===, with one carefully-justified exception.
1 · The surprises of ==
// All true with ==
console.log("" == false); // true
console.log(0 == "0"); // true
console.log(0 == ""); // true
console.log("0" == false); // true
console.log(null == undefined); // true
// All false with ===
console.log("" === false); // false
console.log(0 === "0"); // false
console.log(null === undefined); // falseCoercion rules in == are non-obvious. Use ===; you keep your sanity.
2 · The single useful == case
function isNullish(x) {
return x == null; // true for both null AND undefined
}
console.log(isNullish(null)); // true
console.log(isNullish(undefined)); // true
console.log(isNullish(0)); // false
console.log(isNullish("")); // falsex == null is the idiomatic "is this nullish?" check. Some style guides
still ban it; others permit it. x === null || x === undefined works too. Or
use x ?? defaultValue (next concept).
3 · Object identity vs structural equality
// Objects compare by reference
console.log({a: 1} === {a: 1}); // false — different objects
const x = {a: 1};
console.log(x === x); // true — same object
// Structural — write your own or use a library
function shallowEqual(a, b) {
const ka = Object.keys(a), kb = Object.keys(b);
if (ka.length !== kb.length) return false;
return ka.every(k => a[k] === b[k]);
}
console.log(shallowEqual({a: 1}, {a: 1})); // trueFor deep comparisons use
JSON.stringify(a) === JSON.stringify(b)
(quick but doesn't handle Maps/Sets/dates well), or a library like
lodash.isEqual, or write your own recursive walker.4 · NaN — the one that isn't equal to itself
console.log(NaN === NaN); // false
console.log(Number.isNaN(NaN)); // true — the correct test
console.log(isNaN("abc")); // true — but coerces! "abc" is not NaN per se
console.log(Number.isNaN("abc")); // false — strict testUse Number.isNaN(x), not the global isNaN(x). The global one coerces.
5 · Common mistakes
- Using
==in conditions you don't 100% understand. Always===until you have a reason. - Comparing objects with
===expecting deep equality. It's reference equality. - Forgetting
Number.isNaNoverisNaN. typeof null === "object"— historic; test for null withx === null.
6 · When it clicks
- You never type
==by accident. - You reach for
x == nullintentionally as the nullish check (or??). - You know object equality means reference equality without thinking.
Found this useful?