Numbers
JavaScript has a single number type for integers and decimals alike. It's simple to use, but it has some well-known quirks — tiny rounding errors, special values like NaN and Infinity, and a limit on safe integer size — that every developer runs into sooner or later.
Writing numbers
console.log(42, -7, 3.14); console.log(1_000_000); console.log(2.5e3, 1e-3); console.log(0xff, 0b1010, 0o17);
42 -7 3.14 1000000 2500 0.001 255 10 15
Underscores are visual separators and are ignored. e means "times ten to the power of". The prefixes 0x, 0b and 0o write hexadecimal, binary and octal.
Floating-point precision
Numbers are stored in binary floating point (the IEEE 754 standard), which can't represent most decimal fractions exactly:
console.log(0.1 + 0.2); console.log(0.1 + 0.2 === 0.3); console.log((0.1 + 0.2).toFixed(2)); console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON);
0.30000000000000004 false 0.30 true
This isn't a JavaScript bug — it happens in almost every programming language. For display, round with toFixed. For comparisons, check whether the difference is tiny. For money, store whole cents as integers (1999 instead of 19.99) so sums are exact.
Number methods
const n = 1234.5678; console.log(n.toFixed(2)); console.log(n.toPrecision(3)); console.log(n.toString()); console.log((255).toString(16)); console.log(n.toLocaleString("en-US")); console.log(n.toLocaleString("de-DE"));
1234.57 1.23e+3 1234.5678 ff 1,234.568 1.234,568
toFixed returns a string with a fixed number of decimals — great for display, but convert back with Number() if you need to calculate further. toLocaleString formats numbers the way a particular country expects.
Formatting currency and percentages
Intl.NumberFormat handles currency symbols, separators and rounding for any locale:
const usd = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }); const pct = new Intl.NumberFormat("en-US", { style: "percent", maximumFractionDigits: 1 }); console.log(usd.format(1499.5)); console.log(pct.format(0.256));
$1,499.50 25.6%
NaN — Not a Number
NaN is the result of a calculation that doesn't produce a meaningful number:
console.log(Number("abc")); console.log(0 / 0); console.log(Math.sqrt(-1)); console.log(NaN === NaN); console.log(Number.isNaN(Number("abc"))); console.log(typeof NaN);
NaN NaN NaN false true number
NaN is never equal to anything, even itself, so always test with Number.isNaN(). Oddly, its type is number. Any arithmetic involving NaN also produces NaN, so one bad value can spread through a whole calculation.
Infinity
console.log(1 / 0); console.log(-1 / 0); console.log(Infinity > 1e308); console.log(Number.isFinite(1 / 0));
Infinity -Infinity true false
Safe integers and bigint
Integers are only exact up to Number.MAX_SAFE_INTEGER (about 9 quadrillion). Beyond that, use bigint by adding an n:
console.log(Number.MAX_SAFE_INTEGER); console.log(9007199254740992 + 1); console.log(9007199254740992n + 1n); console.log(Number.isInteger(5.0), Number.isSafeInteger(2 ** 60));
9007199254740991 9007199254740992 9007199254740993n true false
Bigints can't be mixed with ordinary numbers in arithmetic — convert with BigInt(n) or Number(big). They're needed for things like large database IDs and cryptography.
Useful Number properties
| Property / method | Purpose |
|---|---|
Number.isNaN(x) | Is x exactly NaN? |
Number.isFinite(x) | Is x a real, finite number? |
Number.isInteger(x) | Is x a whole number? |
Number.parseFloat(), Number.parseInt() | Read a number from the start of a string (lesson 18) |
Number.MAX_SAFE_INTEGER, Number.EPSILON | Limits of precision |