JavaScript has two different equality operators that look almost identical but behave very differently: == (loose equality) and === (strict equality). Mixing them up is one of the most common sources of subtle bugs for developers new to the language, so it's worth understanding exactly what each one does.
== Performs Type Coercion
Loose equality (==) will convert the operands to the same type before comparing them, which can produce results that feel surprising:
console.log(5 == "5"); // true — string "5" is coerced to number 5
console.log(0 == false); // true — false is coerced to 0
console.log(null == undefined); // true — special case, these two are considered equal
console.log("" == 0); // true — empty string coerced to 0
console.log(" " == 0); // true — whitespace string also coerces to 0!
Output:
true
true
true
true
true
=== Requires Matching Types
Strict equality (===) never coerces — both the value AND the type must match:
console.log(5 === "5"); // false — different types (number vs string)
console.log(5 === 5); // true — same type, same value
console.log(0 === false); // false — number vs boolean
console.log(null === undefined); // false — strict equality treats them as different
Output:
false
true
false
false
Why === Is the Recommended Default
Because =='s coercion rules are genuinely hard to memorize in full (even experienced developers get edge cases wrong), the near-universal convention in modern JavaScript is to use === and !== everywhere, and only reach for == in the rare case where you deliberately want null and undefined to be treated as equal:
function processValue(value) {
// Deliberately using == here to catch BOTH null and undefined in one check
if (value == null) {
return "No value provided";
}
return `Processing: ${value}`;
}
console.log(processValue(undefined));
console.log(processValue(null));
console.log(processValue(0));
Output:
No value provided
No value provided
Processing: 0
Notice processValue(0) correctly falls through to the "Processing" branch — if that check had used if (!value) instead, it would have wrongly treated 0 as "no value," which ties directly into how JavaScript coerces values in general. As a rule of thumb: default to ===, and you'll avoid the vast majority of equality-related bugs.
