JS Foundations #5 — Equality & Type Coercion

Abstract equality algorithm, implicit coercion rules, == vs === edge cases, Object.is, and why [] == ![] is true — all explained with diagrams and runnable examples.

10 min read
JavaScript
Fundamentals
Coercion

TABLE OF CONTENTS
JS Foundations #5 — Equality & Type Coercion

Type coercion is when JavaScript automatically converts a value from one type to another — like turning the number 1 into the string "1", or the other way around. This happens silently in many operations, and if you don't know the rules, the results look like nonsense: [] + {} becomes "[object Object]" and [] == ![] is true.

This article walks through the abstract equality algorithm, implicit vs explicit coercion, and every edge case worth knowing.

Prerequisites: JS Foundations #1 — Variables & Scope


1. == vs === — The Core Difference

=== (strict equality) checks both type and value — no coercion. == (abstract equality) coerces types first, then compares.

Loading editor...

Rule of thumb: always use === unless you specifically want coercion. There's no performance difference worth thinking about.


2. The Abstract Equality Algorithm (The Rules for ==)

When you write x == y, the engine follows these steps in order:

  1. Same type? → Use ===
  2. null == undefined?true
  3. Number vs String? → Convert string to number, compare again
  4. Boolean vs anything? → Convert boolean to number, compare again
  5. Object vs primitive? → Convert object to primitive, compare again
  6. Otherwise → false

Loading editor...


3. The Infamous [] == ![] — Step by Step

Loading editor...

Now you can reason through any coercion puzzle.


4. The + Operator — Addition or Concatenation?

The + operator is overloaded: if either operand is a string, it concatenates. Otherwise, it adds:

Loading editor...

The {} + [] gotcha: when {} appears at the start of a statement, the engine parses it as an empty code block, not an object. The result is +[] which coerces the empty array to 0:

Loading editor...

The key lesson: {} + [] at statement-level is 0, but inside parentheses or function arguments it's "[object Object]". This is a parsing ambiguity, not a coercion rule.


5. Other Arithmetic Operators — -, *, /, %

These operators always coerce to numbers:

Loading editor...


6. The Unary + and - Operators

Unary + coerces its operand to a number. Unary - does the same then negates:

Loading editor...


7. Comparison Operators — <, >, <=, >=

These operators also coerce types. If both operands are strings, they compare lexicographically (dictionary order). Otherwise, both are coerced to numbers:

Loading editor...

The "10" < "2" trap is a common bug when sorting arrays of strings that look like numbers.


8. Explicit Coercion — You're in Control

Implicit coercion is what happens automatically with ==, +, etc. Explicit coercion is when you deliberately convert a type using built-in functions:

Loading editor...

Prefer explicit coercion when you need a specific type. It's clearer and avoids surprises.


9. ToPrimitive — How Objects Become Primitives

When coercion needs a primitive from an object, the engine calls ToPrimitive:

  1. If hint is "string" → try toString() then valueOf()
  2. If hint is "number" or "default" → try valueOf() then toString()

You can control this with Symbol.toPrimitive:

Loading editor...


10. Object.is() — Better Strict Equality

Object.is() is like === but with two corrections:

Loading editor...


11. Truthy and Falsy

The 6 falsy values: false, 0, "", null, undefined, NaN. Everything else is truthy — including [], {}, " ", and -1.

Loading editor...


Key Takeaways

  • === checks type AND value — no coercion. == coerces first.
  • The == algorithm: same type → compare; null/undefined → true; string → number; boolean → number; object → primitive.
  • + is overloaded — if either operand is a string, it concatenates.
  • -, *, /, % always coerce to numbers.
  • Falsy values: false, 0, "", null, undefined, NaN. Everything else is truthy.
  • Object.is() fixes NaN and +0/-0 edge cases in ===.

Next: JS Foundations #6 — Error Handlingtry/catch/finally, custom error classes, and global error handlers.


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI