Problem Solved

JavaScript · == vs ===

Home › Courses › JavaScript › Problems › == vs ===
🟨 Concept · 3 min read

== vs ===.
Coercion or not.

The two equality operators look almost identical. They behave very differently. == converts types before comparing — '5' == 5 is true. === doesn't — '5' === 5 is false. The rule is simple: use === by default. This page covers the coercion rules, the surprising cases, and the one situation where == is acceptable.

Short answer: Use === (strict equality) for everything. It compares value and type without coercion, so '5' === 5 is false. == (loose equality) coerces types first, so '5' == 5 is true — and 0 == '' is also true, which is almost never what you want. The one accepted use of == is value == null to check for both null and undefined in one comparison. Everything else: ===.

✅ The difference in one example

Same values, different result.

equality-basic.js
console.log('5' == 5);   // ?
console.log('5' === 5);  // ?

console.log(0 == '');    // ?
console.log(0 === '');   // ?

console.log(null == undefined);   // ?
console.log(null === undefined);  // ?

console.log(false == '0');   // ?
console.log(false === '0');  // ?
Actual output:

'5' == 5    → true   (string coerced to number)
'5' === 5   → false  (different types)

0 == ''     → true   ('' coerced to 0)
0 === ''    → false  (different types)

null == undefined   → true   (both "empty")
null === undefined  → false  (different types)

false == '0'  → true   ('0' coerced to 0, false to 0)
false === '0' → false  (different types)

✅ == coerces. === doesn't.
✅ Every === is false for different types.
✅ Every == can be true if coercion makes them equal.

The last one is the most surprising: false == '0'
is true because both sides become 0. This is the
kind of result that makes == dangerous.

✅ The coercion rules (simplified)

What == actually does.

coercion.js
// When types differ, == converts to a common type:

// String vs Number → string becomes number
'5' == 5      // true   ('5' → 5)
'5.5' == 5.5  // true   ('5.5' → 5.5)
'abc' == 5    // false  ('abc' → NaN, NaN != 5)

// Boolean vs anything → boolean becomes number
true == 1     // true   (true → 1)
false == 0    // true   (false → 0)
true == '1'   // true   (true → 1, '1' → 1)

// null and undefined → only equal each other
null == undefined   // true
null == 0           // false
undefined == 0      // false

// Object vs primitive → object becomes primitive
[] == ''      // true   ([] → '')
[] == 0       // true   ([] → '' → 0)
[1] == 1      // true   ([1] → '1' → 1)
{} == '[object Object]'  // true
The spec rules for ==, in order:

1. Same type → compare directly (like ===).
2. null == undefined → true.
3. Number vs String → String becomes Number.
4. Boolean vs anything → Boolean becomes Number.
5. Object vs primitive → Object becomes primitive
   (via valueOf or toString).
6. Otherwise → false.

This is why [] == 0 is true:
  [] becomes '' (empty string)
  '' becomes 0 (number)
  0 == 0 → true

And {} == '[object Object]' is true:
  {} becomes '[object Object]' (via toString)

These rules are deterministic and specified.
They are also almost never what you want.

=== has one rule: same type AND same value.
That's it. No coercion, no surprises.

The complexity of == is why style guides
recommend banning it entirely.

✅ The one acceptable use of ==

value == null — checking both null and undefined.

null-check.js
// The explicit way — two checks
if (value === null || value === undefined) {
  // ...
}

// The shorthand — one check with ==
if (value == null) {
  // true if value is null OR undefined
  // false for 0, '', false, NaN
}

// This is the ONLY == pattern that's widely accepted.
// It's intentional — you're explicitly using the
// null == undefined rule.

// But some style guides ban == entirely,
// even this one. Both approaches work.
// Know why you're using it.
value == null:

null      → true
undefined → true
0         → false
''        → false
false     → false
NaN       → false
{}        → false
[]        → false

This is useful for "is this value missing?"
checks, where both null and undefined count
as missing.

It's the one place where == gives you
something === can't — a combined check
for both nullish values.

Some developers use it. Some prefer the
explicit two-check form. Neither is wrong.

The rule: if you use ==, know exactly which
coercion you're relying on. If you can't
explain why it works, use ===.

Don't use == for numbers or strings from user input. This is where == causes the most real bugs. An input field returns a string. input.value == 0 is true when the user types "0", but also when the value is empty (because '' == 0). input.value === 0 is false for both — which is what you want, because the input is a string. Parse first (Number(input.value)), then compare with ===. The same applies to API responses, URL parameters, and anything else that might not be the type you expect. === forces you to be explicit about types.

⚠️ Common mistakes

The equality mistakes that cost real time.

1. Using == everywhere

Coercion causes surprising results. Fix: use ===.

2. Comparing user input with ==

Input is a string; == coerces. Fix: parse first, compare with ===.

3. Expecting === to compare object contents

It compares references. Fix: JSON.stringify or a deep-equal function.

4. Using === for NaN

NaN === NaN is false. Fix: Number.isNaN().

5. value == null without knowing why

It works, but only because of the null/undefined rule. Fix: understand it or use two checks.

6. '' == 0 and '0' == false in conditions

Both are true — almost always a bug. Fix: ===.

7. [] == false in filters

An empty array is truthy in if, but [] == false is true. Fix: use length or ===.

8. Not enforcing with a linter

Style guides say === but code still uses ==. Fix: ESLint eqeqeq rule.

❓ Frequently asked

What is the difference between == and === in JavaScript?

== is loose equality — it compares values after converting them to a common type. '5' == 5 is true because the string is coerced to a number. === is strict equality — it compares both value and type, with no coercion. '5' === 5 is false. The rule: use === by default. It does what you expect and catches bugs earlier.

Why does 0 == '' return true?

Because == coerces both sides to a number. The empty string '' becomes 0, so 0 == 0 is true. This is the kind of surprising behavior that makes == dangerous. Other examples: null == undefined is true, false == '0' is true, [] == false is true. Use === to avoid them.

Does === compare object references or values?

For objects, arrays, and functions, === compares references, not contents. Two objects with the same properties are not === unless they point to the same object in memory. To compare object contents, use JSON.stringify or a deep equality check. This applies to both == and ===.

Is it ever okay to use ==?

One case: checking for null or undefined. value == null is true if value is null OR undefined — a shorthand for the two-check version. Some developers use this intentionally. But even this is debatable. If you use value == null, know exactly why. Otherwise, use ===.

Why do style guides say 'always use ==='?

Because == has too many edge cases to hold in your head. Strings become numbers, booleans become numbers, null and undefined only equal each other, objects become '[object Object]'. Every one of these is a potential bug. === has no coercion — it either matches or it doesn't. ESLint's eqeqeq rule flags == by default.

What about NaN? Does === work?

No. NaN === NaN is false. This is a quirk of the IEEE 754 floating-point spec, not JavaScript-specific. To check for NaN, use Number.isNaN(value) (preferred) or the older isNaN(value). Object.is(NaN, NaN) is also true.

🔗 Continue learning

🗺️ JavaScript learning path
The full roadmap from variables to async — every concept in order

Next in this series:

🕳️ null vs undefined
Two "nothing" values — when to use which, and how to check for them
← All JavaScript problems
Problem solved · JavaScript