Type Coercion and Equality
== vs === (Loose vs Strict Equality)
=== (strict equality): No type conversion. Both type AND value must match.
== (loose equality): Performs type coercion if types differ.
javascript// === never coerces:
1 === 1; // true
1 === '1'; // false — different types
null === undefined; // false
NaN === NaN; // false — NaN is never equal to anything, even itself!
// == coerces:
1 == '1'; // true — '1' coerced to number 1
0 == false; // true — false coerced to 0
0 == ''; // true — '' coerced to 0
null == undefined; // true — special case rule
null == 0; // false — null only equals undefined with ==
NaN == NaN; // false — NaN is still not equal to itselfTruthy and Falsy Values
Every value is either truthy or falsy in a boolean context:
Falsy Values (only 8)
javascriptfalse
0
-0
0n // BigInt zero
'' // empty string
null
undefined
NaNEverything Else is Truthy
javascript// These surprise people:
'0' // truthy! Non-empty string
'false' // truthy!
[] // truthy! Empty array
{} // truthy! Empty object
-1 // truthy! Non-zero number
function(){} // truthy!javascript// Gotcha:
if ([]) console.log('array is truthy'); // logs!
if ({}) console.log('object is truthy'); // logs!
// But:
[] == false; // true — [] is coerced to '' then to 0, false to 0 → 0 == 0
// Even though [] is truthy in boolean context!
// This is why you should NEVER use == with arrays/objectsType Coercion Rules (Abstract Equality ==)
The Abstract Equality Algorithm:
- Same type → use
=== null == undefined→ true (and only these two equal each other)null/undefined == anything_else→ false- If one is a number, coerce the other to number
- If one is a boolean, coerce it to number first
- If one is object and other is string/number/symbol → convert object to primitive
javascript// Rule 4: number vs string
1 == '1' // '1' → 1 → 1 == 1 → true
0 == '' // '' → 0 → 0 == 0 → true
0 == '0' // '0' → 0 → true
// Rule 5: boolean coerced first
true == 1 // true → 1 → 1 == 1 → true
false == 0 // false → 0 → 0 == 0 → true
true == '1' // true → 1, then '1' → 1 → true
false == '' // false → 0, then '' → 0 → true
false == null // false → 0, but rule 3: null only == undefined → false!
// Rule 6: object to primitive
[] == 0 // [] → '' → 0 → 0 == 0 → true
['1'] == 1 // ['1'] → '1' → 1 → true
[1,2] == '1,2' // [1,2] → '1,2' → '1,2' == '1,2' → trueFamous Gotchas
javascriptnull == undefined // true (only case null == something)
null == 0 // false
null == '' // false
null == false // false
NaN == NaN // false — NaN is never equal to anything
NaN === NaN // false
'' == '0' // false — both are strings, no coercion, different values
false == 'false' // false → 0, 'false' → NaN → 0 == NaN → false
false == '0' // false → 0, '0' → 0 → true (!)
// The infamous:
[] == ![] // true!
// Right side: ![] = !true = false → 0
// Left side: [] → '' → 0
// 0 == 0 → trueThe + Operator Coercion
+ is overloaded: numeric addition OR string concatenation.
Rules:
- If either operand is a string → string concatenation
- Otherwise → numeric addition
javascript1 + 2 // 3 (both numbers)
1 + '2' // '12' (string concatenation)
'1' + 2 // '12'
'1' + '2' // '12'
1 + true // 2 (true → 1)
1 + false // 1 (false → 0)
1 + null // 1 (null → 0)
1 + undefined // NaN (undefined → NaN)
1 + [] // '1' ([] → '' → string concat)
1 + {} // '1[object Object]' ({} → '[object Object]' → string concat)
1 + [1,2] // '11,2' ([1,2] → '1,2' → string concat)
// Unary + converts to number:
+'42' // 42
+true // 1
+false // 0
+null // 0
+undefined // NaN
+'' // 0
+[] // 0
+{} // NaN
+[1,2] // NaNObject.is() — The Most Correct Equality
javascript// Fixes two edge cases of ===:
Object.is(NaN, NaN); // true (=== returns false)
Object.is(+0, -0); // false (=== returns true)
// Otherwise same as ===:
Object.is(1, 1); // true
Object.is(1, '1'); // false
Object.is(null, null); // trueComparison Operators and Coercion
javascript// Relational operators always convert to numbers (or string comparison):
'5' > 3 // '5' → 5 → true
'5' < '30' // lexicographic! '5' vs '3' → false (not 5 < 30!)
null > 0 // false (null → 0 for > operator)
null == 0 // false (special == rule: null only equals undefined)
null >= 0 // true (null → 0, 0 >= 0)
// This means: null >= 0 && !(null == 0) — weird!Safe Equality Patterns
javascript// Always prefer === over ==
// Use explicit type checks when needed:
// Check for null OR undefined:
value == null // true for both null and undefined (safe use of ==)
value === null || value === undefined // explicit
// Check for NaN:
Number.isNaN(value) // ✅ — doesn't coerce
isNaN(value) // ❌ — coerces first: isNaN('hello') is true!
// Check numbers:
typeof value === 'number' && !Number.isNaN(value)
// Safe null check before access:
const city = user?.address?.city ?? 'Unknown';Interview Questions
Q: What is the difference between == and ===?
A: === (strict) compares value AND type without coercion. == (loose) performs Abstract Equality algorithm which coerces types. Use === almost always — == only has one common safe use: value == null to check for both null and undefined.
Q: What are all the falsy values in JavaScript?
A: false, 0, -0, 0n, '', null, undefined, NaN. Everything else is truthy, including [], {}, '0', 'false', and -1.
Q: Why is [] == ![] true?
A: ![] is false (truthy array negated). Then [] == false → false coerces to 0, [] coerces to '' then 0. 0 == 0 is true.
Q: When is it safe to use ==?
A: value == null is a common safe pattern to check if value is either null or undefined (the only two values that equal each other with ==, and neither equals anything else). This avoids writing value === null || value === undefined.