06 — Equality — == vs === vs Object.is, and Four Algorithms

5 min read

"Always use triple equals, move on" was my equality strategy, and it worked until it couldn't explain an edge case. The idea that everything else hangs off: there isn't one equality in JavaScript, there are four algorithms under the hood, and ==, ===, and Object.is each pick a different one — differing only on two edge cases. [1]

The framing that finally landed is the ladder of strictness. Reading from loosest to strictest:

algorithm NaN vs NaN +0 vs -0 == (loose) coerces types before comparing false true === (strict) no coercion; types must match false true SameValueZero used by Map, Set, Array.includes true true SameValue — Object.is() strictest; distinguishes the two zero signs true false

The two operators

== (loose equality) compares two values, performing type coercion if the types differ [2]. "5" == 5 is true because the string is converted to a number first. null == undefined is true (a special-case pair). This is the operator that produces "surprising" results — "0" == false is true, "" == 0 is true — because the Abstract Equality Comparison algorithm coerces both sides through a fixed set of rules. My rule is simple: never write ==. The surprises aren't worth the keystroke.

=== (strict equality) compares without coercion [3]. If the types differ, it returns false immediately. Same type, compare values directly. The one famous wrinkle: NaN === NaN is false, and +0 === -0 is true. This is the default for almost all equality checks.

The reason === wins isn't that it's stricter for its own sake — it's that the result is predictable. With == I had to hold the coercion table in my head; with === the question "are these the same type and value?" answers itself.

Object.is — the strictest

Object.is() is the fourth algorithm, SameValue [4]. It behaves like === except it fixes the two edge cases the spec calls out:

  • Object.is(NaN, NaN) → true (where NaN === NaN is false)
  • Object.is(+0, -0) → false (where +0 === -0 is true)

In normal code these differences almost never matter — but when they do, Object.is is the only correct tool. The classic case is NaN: x === NaN is always false, so the idiomatic check is Number.isNaN(x) or, equivalently, Object.is(x, NaN).

SameValueZero — the one you can't call directly

The fourth algorithm, SameValueZero, is the same as Object.is except it treats +0 and -0 as equal [5]. It's not exposed as a function — it's used internally by Map key comparison, Set membership, and Array.prototype.includes(). That's why [NaN].includes(NaN) is true but [NaN].indexOf(NaN) is -1 (indexOf uses ===). When a Set says "I already have this value," it's using SameValueZero under the hood.

The practical upshot: collection lookups are slightly smarter than ===. If I'm checking whether a value is in an array and NaN is a possibility, arr.includes(x) is correct where arr.indexOf(x) !== -1 is not.

How I use this

The rules I actually apply: default to === for every comparison; reach for Object.is only when NaN or signed-zero is genuinely in play (and Number.isNaN for the NaN check reads cleaner); never write ==; and remember that Array.includes, Set, and Map use SameValueZero, which is more forgiving than === on NaN. That covers 100% of the equality decisions in real code. The four-algorithm view matters because it explains why the four differ — and once I could see the two edge cases (NaN and signed zero) as the only variables, equality stopped being a source of doubt.

References

[1] Mozilla, "Equality comparisons and sameness," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness

[2] Mozilla, "Equality (==) operator," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality

[3] Mozilla, "Strict equality (===) operator," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality

[4] Mozilla, "Object.is() — same-value equality," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is

[5] Mozilla, "Same-value-zero equality," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#same-value-zero_equality

Knowledge check · Question 1 of 5

Why is `==` generally avoided in favor of `===`?

Comments

Leave a Comment

You must be signed in to comment

0 Comments

No comments yet. Be the first to comment!