One number type
Every number in JavaScript is a 64-bit float. There is no separate integer type, so 5 and 5.0 are the same value, and integer arithmetic is exact only up to 2^53 − 1 (Number.MAX_SAFE_INTEGER).
Beyond that you need BigInt: 9007199254740993n. You will meet it with database ids and timestamps in nanoseconds, and almost nowhere else.
Floating point
0.1 + 0.2 // 0.30000000000000004
0.1 + 0.2 === 0.3 // false
(0.1 + 0.2).toFixed(2) // "0.30"
// comparing floats
const close = (a, b, eps = 1e-9) => Math.abs(a - b) < eps;
Never store money as a float. Work in integer minor units — kopeks, cents, qəpik — and divide only when you format. Every currency bug you will ever see starts with a float.
Parsing
Number("12.5") // 12.5
Number("12px") // NaN
Number("") // 0 ← the trap
Number(" 12 ") // 12 — whitespace is fine
Number(null) // 0
Number(undefined) // NaN
parseInt("12px", 10) // 12
parseInt("px12", 10) // NaN
parseFloat("1.5rem") // 1.5
Number.isFinite(x) // a real, usable number
Number.isInteger(x)
Number.isNaN(x) // not the global isNaN, which coerces
Rounding
toFixed rounds the binary value, so a number that looks like exactly 2.345 may be stored as 2.34499999…, and you get "2.34". If the rounding must be exact, work in integers.
Math.round(2.5) // 3 — .5 always goes up
Math.round(-2.5) // -2 — which means "up" is towards +∞
Math.floor(2.9) // 2
Math.ceil(2.1) // 3
Math.trunc(-2.9) // -2 — just drops the fraction
Math.floor(-2.9) // -3
// to 2 decimal places, as a number
Math.round(2.345 * 100) / 100 // 2.35 (usually — see below)
(2.345).toFixed(2) // "2.35" as a string, sometimes "2.34"
Math
Math.min(3, 7) Math.max(3, 7)
Math.abs(-4) Math.sign(-4) // 4, -1
Math.pow(2, 10) 2 ** 10 // 1024
Math.sqrt(16) Math.hypot(3, 4) // 4, 5
Math.random() // 0 ≤ n < 1
const clamp = (n, lo, hi) => Math.min(hi, Math.max(lo, n));
const lerp = (a, b, t) => a + (b - a) * t;
const randInt = (lo, hi) => lo + Math.floor(Math.random() * (hi - lo + 1));
Math.random() is predictable. For anything security-related use crypto.getRandomValues() or crypto.randomUUID().
Dates
- Months are zero-based. Days of the month are not. This is the single commonest date bug.
- A bare
"2026-09-21"is parsed as UTC;"2026-09-21T00:00"is parsed as local time. That one character moves a date by a day. - Date arithmetic across months and daylight saving is genuinely hard. For anything beyond "add a day", use
Temporalwhere it is available, or a library.
new Date("2026-09-21") // ISO — parsed as UTC midnight
new Date("21/09/2026") // unreliable; do not do this
new Date(2026, 8, 21) // month is ZERO-based: 8 is September
Date.now() // milliseconds since 1970
const d = new Date();
d.getFullYear(); d.getMonth(); d.getDate(); // getDate is day of month
d.getDay(); // day of week, 0 = Sunday
d.toISOString(); // "2026-09-21T09:00:00.000Z"
Formatting for people
Separators, decimal marks, currency position and month names all differ by locale. Intl knows every one of them and is built into the browser.
new Intl.NumberFormat("az").format(1234.5);
// "1.234,5"
new Intl.NumberFormat("az", { style: "currency", currency: "AZN" }).format(1234.5);
// "1.234,50 ₼"
new Intl.NumberFormat("en", { maximumFractionDigits: 1, notation: "compact" }).format(12400);
// "12.4K"
new Intl.DateTimeFormat("az", { dateStyle: "long" }).format(new Date());
new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(-1, "day"); // "yesterday"