Equality Comparisons
EasyJavaScript has three ways to compare equality: == (loose), === (strict), and Object.is(). Each behaves differently with type coercion, NaN, and signed zeros. Understanding these differences is one of the most frequently tested JavaScript interview topics.
Interactive Visualization
String Immutability
Step 1: Create
let str = "hello";
Output
"hello"
1 / 4
Key Points
- === (strict) compares without type coercion — prefer this by default
- == (loose) performs type coercion before comparing, following complex rules
- Object.is() is like === but handles NaN and +0/-0 correctly
- NaN === NaN is false — use Object.is(NaN, NaN) or Number.isNaN()
- +0 === -0 is true — but Object.is(+0, -0) is false
- Objects are compared by reference, not by value (even with ===)
Code Examples
Strict Equality (===)
// === compares value AND type — no coercion console.log(5 === 5); // true console.log(5 === "5"); // false (different types!) console.log(true === 1); // false (different types!) console.log(null === undefined); // false (different types!) // Reference comparison for objects const a = [1, 2, 3]; const b = [1, 2, 3]; const c = a; console.log(a === b); // false (different objects!) console.log(a === c); // true (same reference)
Strict equality checks both value and type. Objects are compared by reference, not structure.
Loose Equality (==) and Coercion
// == converts types before comparing console.log(5 == "5"); // true (string → number) console.log(0 == false); // true (boolean → number) console.log("" == false); // true (both → 0) console.log(null == undefined); // true (special rule!) console.log(null == 0); // false (null only == undefined) // Surprising results console.log([] == false); // true ([] → "" → 0) console.log("" == 0); // true (both → 0) console.log(" " == 0); // true (" " → 0)
Loose equality follows complex coercion rules. The null == undefined special case is the only useful ==.
Object.is() — The Most Precise
// Object.is() is like === with two fixes: // Fix 1: NaN is equal to itself console.log(NaN === NaN); // false (!) console.log(Object.is(NaN, NaN)); // true // Fix 2: +0 and -0 are different console.log(+0 === -0); // true (!) console.log(Object.is(+0, -0)); // false // Everything else matches === console.log(Object.is(5, 5)); // true console.log(Object.is(5, "5")); // false // Practical: checking for NaN const value = 0 / 0; // NaN console.log(Number.isNaN(value)); // true (preferred) console.log(Object.is(value, NaN)); // true
Object.is() fixes the two quirks of ===: NaN equality and signed zero comparison.
Reference vs Value Equality
// Primitives: compared by value console.log("hello" === "hello"); // true console.log(42 === 42); // true // Objects: compared by reference const obj1 = { name: "Alice" }; const obj2 = { name: "Alice" }; console.log(obj1 === obj2); // false (different objects!) // Checking structural equality requires manual comparison function deepEqual(a, b) { return JSON.stringify(a) === JSON.stringify(b); } console.log(deepEqual(obj1, obj2)); // true
Primitives compare by value, objects by reference. Deep equality requires manual comparison.
Common Mistakes
- Using == when === is appropriate (coercion causes subtle bugs)
- Checking NaN with === (NaN !== NaN — use Number.isNaN() instead)
- Expecting {} === {} to be true (objects compare by reference)
- Not knowing the null == undefined special case (it is sometimes useful)
Interview Tips
- Always default to === and explain why (no type coercion)
- Know the NaN and +0/-0 edge cases — these are classic interview questions
- Explain when == is actually useful: null == undefined to check for both
- Be ready to whiteboard the coercion steps for tricky == comparisons