Written by Rahul · Frontend Engineer at Google · Updated 2025
Short answer: always use ===. Long answer: understanding why will save you from some of the most bizarre bugs in JavaScript.
The Core Difference
===(Strict Equality) — Compares value AND type. No conversions.==(Loose Equality) — Converts types first, then compares. Chaos follows.
// Strict equality — predictable
1 === 1 // true
1 === "1" // false (number vs string)
null === undefined // false
// Loose equality — JavaScript goes wild
1 == "1" // true (string "1" → number 1)
"" == false // true (both → 0)
null == undefined // true (special rule)
[] == false // true ([] → "" → 0, false → 0)
"0" == false // true ("0" → 0, false → 0)
"" == 0 // true ("" → 0)The Type Coercion Madness
Here's the famous table of == insanity:
[] == ![] // true — yes, really
[] == false // true
"" == false // true
0 == false // true
0 == "" // true
0 == "0" // true
"" == "0" // false — wait, what?
// The logic:
// [] == ![]
// [] == false (! converts [] to boolean true, then negates to false)
// "" == false ([] converts to "")
// 0 == 0 ("" and false both convert to 0)
// true!The Only Exception — null Checking
There's exactly ONE case where == is acceptable:
// Check for null OR undefined in one shot
if (value == null) {
// This catches both null and undefined
// Equivalent to: value === null || value === undefined
}
// This is used in some codebases, but I prefer being explicit:
if (value === null || value === undefined) { ... }
// Or even better in modern JS:
if (value ?? "default") { ... }Real Production Bugs from ==
Bug 1: Form Validation
const userInput = document.getElementById("age").value; // Always a string!
// ❌ This "works" but is misleading
if (userInput == 18) { // "18" == 18 is true due to coercion
allowAccess();
}
// What happens when input is empty?
"" == 0 // true! Empty field passes numeric checks
// ✅ Parse explicitly
const age = parseInt(userInput, 10);
if (age === 18) {
allowAccess();
}Bug 2: API Response Checking
const response = await fetch("/api/count");
const data = await response.json(); // { count: 0 }
// ❌ Loose equality treats 0 as falsy
if (data.count == false) {
showEmptyState(); // Shows empty state when count is 0!
}
// ✅ Be explicit
if (data.count === 0) {
showEmptyState();
}Best Practices
- Always use
===and!==— no exceptions (ESLint rule:eqeqeq) - Convert types explicitly —
Number(str),String(num),Boolean(val) - Use nullish coalescing (
??) instead of== nullchecks - Enable ESLint — the
eqeqeqrule catches these automatically
Interview Tip
Know the [] == ![] example and be able to explain the coercion steps. Then say "in practice, I always use strict equality and let the linter enforce it." That shows both knowledge and pragmatism.