Types, Equality and Coercion
Know the eight types, how ToPrimitive, ToNumber and ToString drive implicit conversion, and which equality algorithm each operation uses.
Key points
- 1
There are seven primitive types (undefined, null, boolean, number, bigint, string, symbol) plus objects. typeof has eight results, and its two quirks are null giving "object" and functions giving "function".
- 2
Objects convert through ToPrimitive: Symbol.toPrimitive if present, otherwise valueOf then toString (for the "number" and "default" hints) or toString then valueOf (for the "string" hint). Date treats "default" like "string".
- 3
Binary + concatenates when either primitive operand is a string. Every other arithmetic operator converts to numbers, and template literals and String() always convert to strings.
- 4
Loose equality: null and undefined equal only each other. Booleans convert to numbers first, objects go through ToPrimitive, and strings compared with numbers go through ToNumber.
- 5
There are four equality algorithms. === (NaN never equal, +0 equals -0), SameValueZero (includes, Map and Set: NaN equals NaN), SameValue (Object.is: also separates ±0) and loose ==.
- 6
Numbers are IEEE 754 doubles, exact for integers only up to 2^53 − 1. Use integer minor units or a decimal library for money, and BigInt for large integers. BigInt never mixes implicitly with Number.
- 7
Prefer ?? over || for defaults when 0, "" or false are valid, and remember that JSON round trips drop undefined and functions, and turn Dates into strings, Maps into {} and NaN into null.
Common traps
["1","2","3"].map(parseInt)is[1, NaN, NaN], because map passes the index as the radix.(1.005).toFixed(2)is "1.00", because the stored value is just below 1.005.null >= 0is true butnull == 0is false: relational operators and == use different algorithms.
Read the source
Test yourself on Types, Equality and Coercion
Ten questions, with the answer and explanation after each one.