Part 7 — Type Conversion & Coercion
The three abstract conversions, + is special, The infamous outputs, explained, Truthy and falsy, Explicit conversion (do this instead of relying on coercion) 🟢
ELI12. Coercion is JavaScript quietly changing a value's type to make an operation "work." + with a string means "glue strings," so 1 + "2" becomes "12". - only makes sense for numbers, so "5" - 2 becomes 3. The rules are consistent once you know them — they just look chaotic.
The three abstract conversions#
- ToPrimitive(obj, hint) — objects convert by calling
Symbol.toPrimitive, thenvalueOf/toString(order depends on hint"number"/"string"/"default"). - ToNumber —
""→0," 12 "→12,"12x"→NaN,true→1,false/null→0,undefined→NaN,[]→0,[5]→5,[1,2]→NaN,{}→NaN. - ToString — arrays join with commas (
[1,2]→"1,2",[]→""), objects →"[object Object]",null→"null".
+ is special#
+ means addition only if both operands are numbers/bigints after ToPrimitive; otherwise it's string concatenation. Every other arithmetic operator forces ToNumber.
The infamous outputs, explained#
[] + [] // "" → []→"" , ""+"" = ""
[] + {} // "[object Object]" → ""+"[object Object]"
{} + [] // 0 at statement start ⚠️
// {} is an empty BLOCK, then +[] → ToNumber([]) → 0
// as an expression: ({}) + [] === "[object Object]"
"5" - 2 // 3 → "-" forces numbers: 5 - 2
"5" + 2 // "52" → "+" with a string concatenates
true + true // 2 → true→1, 1+1
null + 1 // 1 → null→0
undefined + 1 // NaN → undefined→NaN
NaN == NaN // false → NaN is never equal to anything, even itself
1 + "2" + 3 // "123" → left-to-right: "12" then "123"
1 + 2 + "3" // "33" → 3 then "33"
[] == ![] // true ⚠️ → ![] is false → [] == false → "" == 0 → 0 == 0
"" == 0 // true → "" → 0
[null] == "" // true → [null] → ""
The {} + [] result depends entirely on context (statement vs expression) — the #1 "gotcha" people misquote. 🎯
Truthy and falsy#
Only 8 falsy values exist, memorize them:
false, 0, -0, 0n, "", null, undefined, NaN
Everything else is truthy — including "0", "false", [], {}, and function(){}.
if ([]) console.log("runs — empty array is truthy");
if ({}) console.log("runs — empty object is truthy");
if ("0") console.log("runs — non-empty string is truthy");
Boolean("") // false
!!"hello" // true (double-bang → boolean)
Explicit conversion (do this instead of relying on coercion) 🟢#
Number("42") // 42 (NaN on failure)
parseInt("42px") // 42 (stops at non-digit; give a radix: parseInt("0x1",16))
parseFloat("3.14abc") // 3.14
String(42) // "42"
(42).toString(2) // "101010" (binary)
Boolean(x) / !!x
Array.from("abc") // ["a","b","c"]
JSON.parse / JSON.stringify // structured
Interview questions (Part 7):
- List all falsy values.
- Explain
[] + {}vs{} + []. - Why does
"5" + 2differ from"5" - 2? - Walk through
[] == ![]step by step.