Lesson 1 of 5
Values, types and the traps of coercion
2 min read
JavaScript has primitive types (string, number, bigint, boolean, undefined, null, symbol) and objects (everything else: arrays, functions, dates, maps). Primitives are copied by value; objects are passed by reference.
let a = 5; let b = a; b++; // a is still 5
const x = { n: 1 }; const y = x; y.n = 2; // x.n is now 2: same objecttypeof quirks
typeof null // "object" (a historic bug)
typeof [] // "object" → use Array.isArray([])
typeof function(){} // "function"
typeof NaN // "number"== vs ===
=== compares value and type with no conversion. == converts types first, using rules almost nobody remembers fully:
0 == "" // true
"1" == 1 // true
null == undefined // true
null == 0 // false
[] == false // true
NaN == NaN // false (NaN is never equal to anything; use Number.isNaN)Answer to give: "I always use ===. The only == I'd accept is x == null, which checks for both null and undefined."
Truthy and falsy
Falsy values: false, 0, -0, 0n, "", null, undefined, NaN. Everything else is truthy, including "0", "false", [] and {}.
|| returns the first truthy value; ?? (nullish coalescing) returns the right side only for null or undefined:
const qty = 0;
qty || 10 // 10 (0 is falsy: probably a bug)
qty ?? 10 // 0
user?.address?.city // optional chaining: undefined instead of a crashNumbers
All numbers are 64-bit floating point. 0.1 + 0.2 === 0.30000000000000004. For money, store integers (paise) or use a decimal library. Number.MAX_SAFE_INTEGER is 2^53 − 1; beyond that use BigInt.
var, let and const
| Scope | Hoisting | Re-assign | Re-declare | |
|---|---|---|---|---|
var | function | hoisted, initialised to undefined | yes | yes |
let | block | hoisted, but in the temporal dead zone until declared | yes | no |
const | block | same as let | no | no |
const stops re-assignment, not mutation: const arr = []; arr.push(1) is fine.
console.log(a); // undefined (var is hoisted)
var a = 1;
console.log(b); // ReferenceError: cannot access 'b' before initialization
let b = 2;Function declarations are hoisted completely (you can call them before they appear); function expressions and arrow functions assigned to let/const are not.
Check yourself
- What does
typeof nullreturn and why is it surprising? - Give three falsy values that beginners think are truthy, and one truthy value they think is falsy.
- When would
||give the wrong default where??is right?
Sign up free to save your progress.