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

JS literals.js
console.log(42, -7, 3.14);
console.log(1_000_000);
console.log(2.5e3, 1e-3);
console.log(0xff, 0b1010, 0o17);
Output
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:

JS precision.js
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);
Output
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

JS methods.js
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"));
Output
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:

JS intl.js
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));
Output
$1,499.50
25.6%

NaN — Not a Number

NaN is the result of a calculation that doesn't produce a meaningful number:

JS nan.js
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);
Output
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

JS infinity.js
console.log(1 / 0);
console.log(-1 / 0);
console.log(Infinity > 1e308);
console.log(Number.isFinite(1 / 0));
Output
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:

JS bigint.js
console.log(Number.MAX_SAFE_INTEGER);
console.log(9007199254740992 + 1);
console.log(9007199254740992n + 1n);
console.log(Number.isInteger(5.0), Number.isSafeInteger(2 ** 60));
Output
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 / methodPurpose
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.EPSILONLimits of precision

Try it yourself

Try it yourself
Console output