Equality of
Values
Without a clear model of equality, every day is a masked carnival — you can't tell if you're talking to the same value twice or to two different ones. Good news: we already did the hard part by counting. Equality falls right out of it. Same shape on the diagram means the same value.
Pick two values. Watch the three equalities decide
Click a slot, then click a value to fill it. The diagram shows whether the two land on the same shape. The three operators report their verdicts — and the rare cases where === disagrees with same-value light up the explanation.
Three kinds of equality
JavaScript has several equalities. We'll explain the least-known one first, because it maps directly onto our mental model — then use it to explain the rest.
- Same-value equality —
Object.is(a, b) - Strict equality —
a === b(and its opposite!==) - Loose equality —
a == b(usually avoided)
console.log(Object.is(2, 2)); // true console.log(Object.is({}, {})); // false
Same value = same shape
Object.is(a, b) is true exactly when a and b point at the same shape on our diagram — the same single value.
Recall the counting sketch:
let dwarves = 7; let continents = '7'; let worldWonders = 3 + 4;
Object.is(dwarves, continents)→ false — number7and string'7'are different values.Object.is(continents, worldWonders)→ false — different values again.Object.is(worldWonders, dwarves)→ true —3 + 4summons the same7asdwarves.
Objects need no extra concept. {} always creates a new value, so two separately-written {} are two shapes — never equal. It all falls straight out of the model. Try it in the lab above with the two {} chips.
On our diagram, the same value can't appear twice. Object.is(a, b) is true precisely when a and b sit on the same shape.
Strict equality, and its two exceptions
In practice you'll use === most. It matches Object.is in almost every case — with two irregular verbs to memorise.
console.log(2 === 2); // true console.log({} === {}); // false
Exception 1 · NaN
NaN === NaN is false, even though they're the same value. So this check never fires:
function resizeImage(size) { if (size === NaN) { // always false — broken! console.log('Something is wrong.'); } }
Three ways that actually detect NaN (all work):
Number.isNaN(size) Object.is(size, NaN) size !== size // NaN is the only value not equal to itself
That last one is the punchline of the whole chapter — sit with it.
Exception 2 · negative zero
0 === -0 and -0 === 0 are both true, yet they are different values:
let width = 0; let height = -width; // -0 console.log(width === height); // true console.log(Object.is(width, height)); // false
These are uncommon — Dan reports never hitting the -0 case in his whole career. Just know they exist so you recognise them. For everything else, "same value" intuition serves both Object.is and ===.
Loose equality: the bogeyman
== coerces its operands by arcane rules. It's widely considered an early design mistake. Don't memorise it.
console.log([[]] == ''); // true console.log(true == [1]); // true console.log(false == [0]);// true
Wait, what?! Many style guides ban == outright. We won't cover its rules — they don't enrich the mental model and you'll want that memory for other topics. Try '7' against 7 in the lab: === says false, but == coerces them to true. That gap is the argument against it in one click.
One == usage is common and worth knowing:
if (x == null) { /* ... */ } // equivalent to: if (x === null || x === undefined) { /* ... */ }
Even that can be controversial — agree as a team how much == you tolerate.
Recap
- Same-value
Object.is(a, b)matches "same shape on the diagram". The same value can't appear twice. - Strict
===is what you'll use. It equalsObject.isexcept:NaN === NaNis false, and0 === -0is true. - Detect
NaNwithNumber.isNaN(x)— or the elegantx !== x. - Loose
==is arcane and usually avoided; the one handy case isx == null.
Why is size !== size a NaN test? Because NaN === NaN is false, so NaN !== NaN is true — and NaN is the only value not equal to itself. Ensuring that test would work was one of the original reasons NaN === NaN was made false, decided before JavaScript even existed.