In programming, comparisons help us make decisions. JavaScript offers several mechanisms for comparing values, each with its own behavior. This article explores the subtleties of equality and identity in JS.
The most common comparison asks: “Is value X the same as value Y?” But in JS, “same” can mean different things depending on context. The === operator, known as strict equality, checks both value and type — without coercion:
3 === 3.0; // true
"yes" === "yes"; // true
42 === "42"; // false
true === 1; // false
null === undefined; // falseWhile === avoids type coercion, it has quirks — especially with NaN and -0.
NaN === NaN; // false
0 === -0; // trueTo compare these values accurately, use:
Number.isNaN(NaN); // true
Object.is(-0, 0); // false
Object.is(NaN, NaN); // trueObject.is(..) is like a “quadruple-equals” — a truly strict comparison that doesn’t lie.
Object comparisons in JS use reference identity, not structure or content:
[1, 2, 3] === [1, 2, 3]; // false
{ a: 42 } === { a: 42 }; // false
(x => x * 2) === (x => x * 2); // falseEven if two objects look identical, they are different if they are separate instances.
var x = [1, 2, 3];
var y = x;
y === x; // true
y === [1, 2, 3]; // falsex and y point to the same array, so they are equal. But comparing to a new array fails, even if the contents match.
JavaScript does not provide built-in structural equality for objects. You must implement it manually — and it’s complex. For example, comparing two functions structurally is nearly impossible due to closures and context.
Comparisons in JavaScript are nuanced. === works well for most cases, but for special values like NaN and -0, use Object.is(..) or Number.isNaN(..). For objects and functions, JS compares references, not structure. Understanding these distinctions helps you write more accurate and predictable code.