JavaScript Interview Prep
Type System & Coercion

== vs ===

The Strict vs Lenient Librarian

LinkedIn Hook

[] == false is true.

[] == ![] is also true.

But if ([]) runs the truthy branch — because [] is truthy.

How can [] be "equal to false" and "truthy" at the same time? The answer is the == algorithm, spelled out line by line in the ECMAScript spec.

Once you learn the 5 coercion steps == runs, every trick question becomes a mechanical walkthrough. And once you know the one legitimate reason to still use == in modern code, you stop memorizing and start reasoning.

In this lesson you'll learn the exact difference between == and ===, walk through the algorithm on real examples, decode [] == ![] step by step, and see a full comparison table of common coercions.

If an interviewer ever smirks and writes [] == ![] on the whiteboard — this lesson is your cheat code.

Read the full lesson -> [link]

#JavaScript #InterviewPrep #EqualityOperators #TypeCoercion #Frontend #CodingInterview #WebDevelopment


== vs === thumbnail


What You'll Learn

  • The mechanical difference between === (strict) and == (abstract) equality
  • The 5 coercion rules == applies, in order, from the ECMAScript spec
  • Step-by-step walkthroughs of [] == false and [] == ![], plus the one valid modern use of ==

Strict vs Lenient Librarian

Think of === as a strict librarian who checks both your name AND your ID photo. If either doesn't match, you're rejected. == is the lenient librarian who says "close enough" — if your name sounds similar, she'll let you through after checking a conversion chart.

Strict Equality (===)

=== checks type AND value. No coercion, no surprises:

5 === 5;            // true -- same type, same value
5 === "5";          // false -- different types, stop immediately
true === 1;         // false -- boolean !== number
null === undefined; // false -- different types
NaN === NaN;        // false -- NaN is not equal to anything, including itself!

Abstract Equality (==) — The Coercion Algorithm

== follows a specific algorithm from the ECMAScript spec. Here are the key rules:

Step 1: If types are the same       -> behave like ===
Step 2: null == undefined           -> true (special rule)
Step 3: If comparing number & string -> convert string to number
Step 4: If one side is boolean       -> convert boolean to number first
Step 5: If one side is object & other is primitive -> ToPrimitive(object)

Walking Through the Algorithm

// Example 1: "5" == 5
// Types: string vs number
// Rule: convert string to number -> Number("5") = 5
// Now: 5 == 5 -> true
"5" == 5;  // true

// Example 2: true == 1
// Types: boolean vs number
// Rule: convert boolean to number -> Number(true) = 1
// Now: 1 == 1 -> true
true == 1;  // true

// Example 3: true == "1"
// Types: boolean vs string
// Rule: convert boolean to number -> Number(true) = 1
// Now: 1 == "1"
// Rule: convert string to number -> Number("1") = 1
// Now: 1 == 1 -> true
true == "1";  // true

// Example 4: null == undefined
// Special rule: null and undefined are == to each other and NOTHING else
null == undefined; // true
null == 0;         // false
null == "";        // false
null == false;     // false
undefined == 0;    // false
undefined == "";   // false

The Notorious [] == false and [] == ![]

// Why [] == false is true:
// Step 1: boolean to number -> false becomes 0
// Now: [] == 0
// Step 2: ToPrimitive([]) -> [].toString() -> ""
// Now: "" == 0
// Step 3: string to number -> Number("") -> 0
// Now: 0 == 0 -> true
[] == false;  // true

// Why [] == ![] is true:
// Step 0: ![] evaluates first. [] is truthy, so ![] = false
// Now: [] == false
// (same steps as above)
// Result: true
[] == ![];  // true

// Why this is insane -- both sides are "equal" to false,
// but the array itself is truthy:
if ([]) console.log("truthy!");       // "truthy!" -- [] IS truthy
if ([] == false) console.log("wat");  // "wat" -- but == says it equals false

Common == Comparison Table

+-----------------------+---------+----------+
| Comparison            | ==      | ===      |
+-----------------------+---------+----------+
| 5 == "5"              | true    | false    |
| 0 == ""               | true    | false    |
| 0 == false            | true    | false    |
| "" == false           | true    | false    |
| null == undefined     | true    | false    |
| null == 0             | false   | false    |
| NaN == NaN            | false   | false    |
| [] == false           | true    | false    |
| [] == ![]             | true    | false    |
| "" == []              | true    | false    |
| 0 == []               | true    | false    |
| false == "0"          | true    | false    |
| false == ""           | true    | false    |
+-----------------------+---------+----------+

== vs === visual 1


Common Mistakes

  • Using == "because it's shorter" — the coercion algorithm has at least five branches and leads to bugs that === simply can't produce.
  • Assuming null == 0 or undefined == 0 — both are false. null and undefined are only == to each other, nothing else.
  • Forgetting the NaN rule when debugging — NaN == NaN, NaN === NaN, NaN == anything are all false. Use Number.isNaN(x) to check.

Interview Questions

Q: Explain the difference between == and ===.

=== (strict equality) checks both type and value with no coercion. == (abstract equality) allows type coercion before comparison -- it follows a specific algorithm that converts types to match before comparing values.

Q: Why does [] == ![] return true?

First, ![] evaluates to false (since [] is truthy). So it becomes [] == false. The boolean false converts to 0. Then ToPrimitive([]) produces "". Then Number("") is 0. So 0 == 0 is true.

Q: Is there any case where == is useful?

The most legitimate use is value == null, which checks for both null and undefined in a single comparison. This is commonly accepted even in strict codebases. Beyond that, === is preferred for clarity.

Q: What does null == undefined return? What about ===?

null == undefined is true because the spec has a special rule that null and undefined are loosely equal to each other (and to nothing else). null === undefined is false because they are distinct types.

Q: Walk through why [] == ![] is true.

![] is evaluated first. [] is truthy, so ![] is false. The expression becomes [] == false. The == algorithm converts false to 0, giving [] == 0. ToPrimitive([]) returns "". Now "" == 0. The string is converted to a number: Number("") is 0. Finally 0 == 0 is true.


Quick Reference — Cheat Sheet

== vs === -- QUICK MAP

===  strict equality
  - no coercion
  - checks type FIRST, then value
  - NaN === NaN is false

==   abstract equality (coercion algorithm)
  1. same types       -> act like ===
  2. null == undefined -> true (special)
  3. number vs string -> string -> number
  4. boolean side     -> boolean -> number first
  5. object vs prim   -> ToPrimitive(object)

Rule of thumb:
  default: use ===
  exception: value == null  (checks null AND undefined)

Famous traps:
  [] == false   -> true   (but [] is truthy!)
  [] == ![]     -> true
  0 == "0"      -> true
  NaN == NaN    -> false
  null == 0     -> false  (null only == undefined)

Previous: Type Coercion -> The Overly Helpful Translator Next: Truthy / Falsy -> The Nightclub Bouncer


This is Lesson 8.3 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.

On this page