3. Values and types: primitives, coercion, == vs ===
JavaScript has exactly 8 types: 7 primitives (undefined, null,
boolean, number, bigint, string, symbol) plus object (which
includes arrays, functions, dates, maps, sets — everything non-primitive).
typeof undefined // "undefined"
typeof null // "object" <- famous historical bug, kept forever for compatibility
typeof 42 // "number"
typeof 42n // "bigint"
typeof "hi" // "string"
typeof true // "boolean"
typeof Symbol() // "symbol"
typeof {} // "object"
typeof [] // "object" <- arrays are objects; use Array.isArray()
typeof function(){} // "function" (a callable object)
number is a single IEEE-754 double-precision float type for everything
— there's no separate int type, which is why 0.1 + 0.2 === 0.30000000000000004
and why integers beyond Number.MAX_SAFE_INTEGER (2^53 − 1) lose precision.
BigInt (42n) exists specifically to represent arbitrary-precision integers
when that matters (crypto, large IDs).
Coercion is JavaScript converting a value's type implicitly to make an
operation work. == (loose equality) coerces; === (strict equality) never
does — always use === unless you have a specific, commented reason not to.
"5" == 5 // true — string coerced to number
null == undefined // true — special-cased, both "nullish"
0 == false // true — boolean coerced to number
"" == 0 // true — both coerce to 0
[] == false // true — array -> string "" -> number 0
"5" === 5 // false — no coercion, different types
null === undefined // false
Memorize the two == exceptions worth keeping (null == undefined is a
genuinely useful "is this nullish" check) and otherwise ban == via
ESLint's eqeqeq rule — the coercion table is not something anyone should
rely on from memory in review.