skip to content

In JavaScript, what does the == (loose equality) operator do that === does not, and what do '5' == 5 and '5' === 5 each evaluate to?

level: juniorimportance: must knowfreq 86%

answer

  1. one converts, the other refuses
  2. same type means no conversion at all
  3. the string side becomes a number
  4. '5' == 5 versus '5' === 5

basics

~20 s

The == operator converts operands to a common type before comparing; === requires matching types and never converts. So '5' == 5 is true, because the string is converted to the number 5, while '5' === 5 is false.

solid answer

~40 s

`==` runs the abstract (loose) equality algorithm: if both operands are already the same type it behaves exactly like `===`, and otherwise it converts one side and retries the comparison. `===` compares the types first and returns `false` immediately when they differ — no conversion ever happens. So `'5' == 5` is `true`, because the string operand goes through ToNumber and becomes `5`, then `5 == 5`; `'5' === 5` is `false`, because a string is never strictly equal to a number. The practical rule is to default to `===` so a comparison says exactly what it means, and to use `==` only in a deliberate, documented case. If you do write `==`, be able to say which operand got converted and into what — that is what the interviewer is actually checking.

code

javascript · 7 lines
javascript
console.log('5' == 5);           // true  - string converted to number
console.log('5' === 5);          // false - different types
console.log(0 == false);         // true  - boolean converted to number
console.log(0 === false);        // false
console.log(null == undefined);  // true  - special rule
console.log(null === undefined); // false
console.log({} == {});           // false - same type, compared by reference

go deeper

for a junior

Be able to say plainly that == converts before comparing and === does not, and to predict '5' == 5 as true and '5' === 5 as false. Say you default to === in your own code.

for a middle

Explain the mechanics: same-type operands delegate to strict equality, a string compared with a number goes through ToNumber, and booleans become 1 or 0. Predict '' == 0 and '' == '0' correctly.

for a senior

Show where loose equality actually causes production bugs — string-typed inputs compared against numbers, comparisons against false that also match 0 and '' — and describe converting explicitly at the boundary instead.

for a principal

Own the codebase-wide position: a lint rule banning == with one narrow carve-out, explicit parsing at system edges so types are known inside, and the argument for why non-transitive equality is a maintainability risk rather than a style preference.

## Two operators, one difference JavaScript has two equality operators. `===` is strict equality: it looks at the types of the two operands and, if they differ, the answer is `false` with no further work. `==` is loose equality, defined in the specification as the abstract equality comparison. It is not "a sloppier ===": it is a small algorithm that tries to bring the two operands to a comparable form and only then compares them. The crucial thing to internalise is that `==` is a *superset* of `===` in one specific sense: **when both operands already have the same type, `==` delegates to strict equality**. `'a' == 'a'`, `1 == 1`, `null == null`, `NaN == NaN` — all of these are decided by the strict rules, so `NaN == NaN` is `false` just as `NaN === NaN` is. Coercion only enters the picture when the two types differ. ## What == does when the types differ The algorithm is short enough to memorise as a sequence of checks: 1. **Same type** → compare strictly, done. 2. **null and undefined** are loosely equal to each other, and to nothing else. Neither is ever converted. 3. **Number vs String** → convert the string with ToNumber, then retry. 4. **Boolean on either side** → convert that boolean with ToNumber (`true` becomes `1`, `false` becomes `0`), then retry. 5. **Object vs a primitive** (number, string, bigint, symbol) → convert the object to a primitive, then retry. 6. Anything left over → `false`. There is also a rule for comparing a BigInt with a Number or a numeric string, which compares mathematical values, so `1n == 1` is `true` while `1n === 1` is `false`. Two consequences fall straight out of this list. First, **booleans and strings both end up as numbers**, which is why `'0' == false` is `true`. Second, **two objects are never coerced against each other** — they are the same type, so step 1 applies and references are compared: `{} == {}` and `[] == []` are both `false`. ## Worked cases ```js console.log('5' == 5); // true — ToNumber('5') is 5 console.log('5' === 5); // false — string vs number console.log(0 == false); // true — ToNumber(false) is 0 console.log('' == 0); // true — ToNumber('') is 0 console.log('' == '0'); // false — same type, compared as text console.log(null == undefined); // true — the special rule console.log(null == 0); // false — null is never converted ``` The pair `'' == 0` (true), `'0' == 0` (true), `'' == '0'` (false) is worth remembering because it shows that `==` is **not transitive**. Transitivity is something people unconsciously assume of an equality operator, and its absence is exactly why loose equality causes bugs that survive review. ## Why interviewers ask this The question separates candidates who reason from the algorithm from candidates who have memorised folklore. Folklore says "`==` compares value and `===` compares value and type" — a phrasing that is close enough to sound right and useless for predicting `'0' == false` or `[] == 0`. The algorithmic answer predicts every case, including the ones that look bizarre. A second reason is that the conversion is asymmetric in practice. In `'5' == 5` the *string* is converted, never the number. Candidates who say "both get turned into strings" will confidently mispredict `'0' == 0` versus `'' == '0'`. ## Where it bites in real code The classic production bug is a value that arrives as a string — a query parameter, a form field, a value read out of a text-based store — and is compared with `==` against a number. It works, so nobody notices the type is wrong, until an empty field arrives and `'' == 0` quietly reports true, or `'0'` is treated as falsy elsewhere in the same function. Another is a comparison against `false` intended as a "did the user answer no" check, which also matches `0`, `''`, `'0'` and `[]`. ## The rule to state out loud Use `===` by default. Convert explicitly — `Number(input) === 5`, `String(id) === key` — so the conversion is visible in the code rather than hidden in the operator. Reserve `==` for cases where you can articulate the coercion, the best-known being `x == null` as a compact check for "null or undefined". Everything else is better written as an explicit conversion plus a strict comparison.

  • If == and === behave identically when the operands share a type, is there any case where === is true but == is false?
    No. `==` starts by delegating to strict equality whenever the types match, and every other branch only adds ways for the comparison to succeed. So `===` returning true always implies `==` returns true; loose equality is strictly more permissive. The reverse is not true: `'5' == 5` is true while `'5' === 5` is false.
  • Is === faster than == because it skips the conversion work?
    Performance is not the reason to prefer `===`. In practice engines optimise both, and when the operand types already match `==` does the same work as `===` anyway. Choose `===` because it is predictable and self-documenting: the comparison fails loudly when the types are wrong instead of silently converting and hiding a type bug.
  • What does == do when both operands are objects?
    Nothing special — they are the same type, so it falls through to strict equality and compares references. `[] == []` and `{} == {}` are both false because each literal creates a distinct object. Coercion of an object only happens when the *other* operand is a primitive.

saying these in an interview costs you the question

  • == compares values while === compares references
  • Both operands are converted to strings before comparing
  • === is preferred mainly because it runs faster
  • == ignores the types entirely, so anything can match
  • Two identical object literals are loosely equal

context