== vs ===
The Strict vs Lenient Librarian
LinkedIn Hook
[] == falseistrue.
[] == ![]is alsotrue.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
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
[] == falseand[] == ![], 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 |
+-----------------------+---------+----------+
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 == 0orundefined == 0— both arefalse.nullandundefinedare only==to each other, nothing else. - Forgetting the
NaNrule when debugging —NaN == NaN,NaN === NaN,NaN == anythingare allfalse. UseNumber.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 tofalse(since[]is truthy). So it becomes[] == false. The booleanfalseconverts to0. ThenToPrimitive([])produces"". ThenNumber("")is0. So0 == 0istrue.
Q: Is there any case where == is useful?
The most legitimate use is
value == null, which checks for bothnullandundefinedin 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 == undefinedistruebecause the spec has a special rule thatnullandundefinedare loosely equal to each other (and to nothing else).null === undefinedisfalsebecause they are distinct types.
Q: Walk through why [] == ![] is true.
![]is evaluated first.[]is truthy, so![]isfalse. The expression becomes[] == false. The==algorithm convertsfalseto0, giving[] == 0.ToPrimitive([])returns"". Now"" == 0. The string is converted to a number:Number("")is0. Finally0 == 0istrue.
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.