Strict Equality and Comparison
Compare values with ===, Object.is, and relational operators — and know when references matter more than contents.
Comparing values sounds simple until objects, NaN, and API payloads enter the picture. This lesson goes deeper than "use triple equals" — you will understand reference identity, when Object.is beats ===, and why sorting strings with < is not the same as sorting for humans.
Why strict equality is the default
Lesson 5 showed why == coerces types. In production and interviews, === is the baseline: same type and same value, full stop. Special cases still exist — NaN !== NaN, and +0 === -0 even though they behave differently in some math edge cases. null and undefined are different types, so null === undefined is false even though both mean "no useful value" in loose checks.
true
false
false
true
true
false
false
trueObject.is — SameValue equality
Object.is implements SameValue equality — the spec's notion of "are these interchangeable?" It matches === except NaN equals NaN and +0 does not equal -0. Map keys use SameValueZero (like Object.is but treats +0 and -0 as equal). For everyday app code you may never call Object.is, but libraries comparing cache keys or memoized args rely on these semantics.
| Expression | === | Object.is |
|---|---|---|
| NaN, NaN | false | true |
| +0, -0 | true | false |
| 1, 1 | true | true |
| "a", "a" | true | true |
true
false
false
downReference equality for objects and arrays
Objects and arrays compare by reference — identity, not shape. Two literals with identical contents are different objects in memory, so === is false. React uses Object.is internally in some paths because referential equality is how it detects "did this state object change?" Shallow equal compares top-level keys; deep equal walks nested structure — choose based on performance and correctness.
false
true
false
trueRelational operators (<, >, <=, >=)
The example below demonstrates "Relational operators (<, >, <=, >=)" in runnable form. Read the comment lines first — they map each step to the mental model from earlier sections, then trace execution top to bottom as the engine would.
true
true
true
true
true
falseSafe comparison checklist
Relational operators compare after ToNumeric or lexicographic string rules. String comparison is character-by-character Unicode code unit order — "10" < "9" because "1" < "9", which breaks naive sorting of numeric strings. For user-visible sorting use localeCompare with locale and numeric options. Mixing types in < and > triggers coercion; avoid it.
- Same primitive type? Use ===
- Need to detect NaN? Use Number.isNaN(x)
- Compare object contents? Use deep/shallow helper or serialize
- Sort strings for users? Use localeCompare, not <
- Never compare unrelated types without explicit conversion
Production codebases standardize on === and explicit conversion helpers (Number(), String()) at system boundaries. Code review should flag == unless there is a documented legacy reason. Pair strict equality with lint rules like eqeqeq so mistakes never reach main.
- 1=== compares type and value; null and undefined are distinct
- 2Object.is handles NaN and signed zero where === fails
- 3Objects/arrays equal only when references match
- 4Next lesson: if/else, switch, and ternary control flow