JavaScript Number Methods
JavaScript has two distinct sets of numeric helpers: instance methods on numbers themselves ((3.14).toFixed(2)) and static utilities on the Number global (Number.isInteger(x)). Plus a handful of legacy globals (parseInt, parseFloat, isNaN) that you’ll see in old code. This chapter is the reference for all three families.
Instance Methods — Called on a Number
| Method | Returns | Example |
|---|---|---|
toString(radix?) |
String form | (255).toString(16) → "ff" |
toFixed(digits) |
String with fixed decimals | (3.14159).toFixed(2) → "3.14" |
toPrecision(digits) |
String with N significant digits | (1234.5).toPrecision(3) → "1.23e+3" |
toExponential(digits?) |
Scientific notation string | (1234).toExponential(2) → "1.23e+3" |
toLocaleString(loc?, opts?) |
Locale-aware display | (1234).toLocaleString("en") → "1,234" |
valueOf() |
Primitive value | Rarely used directly |
toString(radix)
Convert a number to a string, optionally in a different base (2–36):
(42).toString() // "42"
(255).toString(16) // "ff"
(255).toString(2) // "11111111"
(10).toString(8) // "12"
(3.14).toString() // "3.14"
// Wrap negatives in parentheses or assign to a variable:
const x = -42;
x.toString(); // "-42"
(-42).toString(); // "-42"
-42.toString(); // ❌ SyntaxError — parsed as -(42.toString())
toFixed(digits)
Round to a fixed number of decimal places. Returns a string.
(3.14159).toFixed(2) // "3.14"
(3.14159).toFixed(0) // "3"
(1).toFixed(2) // "1.00"
(1.005).toFixed(2) // "1.00" ← surprising! float precision
(1.5).toFixed(0) // "2" ← banker's rounding edge cases vary
// Convert back if you need a number
Number((3.14159).toFixed(2)); // 3.14
+(3.14159).toFixed(2); // 3.14
Warning: toFixed returns a string, not a number. Don’t use it for math; convert back with Number() or unary +.
toPrecision(digits)
Total significant digits, not decimal places.
(123.456).toPrecision(2) // "1.2e+2"
(123.456).toPrecision(5) // "123.46"
(0.001234).toPrecision(2) // "0.0012"
toExponential(digits?)
Scientific notation.
(1234).toExponential() // "1.234e+3"
(1234).toExponential(2) // "1.23e+3"
(0.001234).toExponential() // "1.234e-3"
toLocaleString(locale?, options?)
The everyday formatter for humans. Locale-aware, supports currency, percent, and units.
(1234567.89).toLocaleString() // depends on system locale
(1234567.89).toLocaleString("en-US") // "1,234,567.89"
(1234567.89).toLocaleString("de-DE") // "1.234.567,89"
(1234567.89).toLocaleString("hi-IN") // "12,34,567.89"
(0.4321).toLocaleString("en", { style: "percent" });
// "43%"
(1999.99).toLocaleString("en", {
style: "currency",
currency: "USD"
});
// "$1,999.99"
(1024).toLocaleString("en", {
style: "unit",
unit: "megabyte"
});
// "1,024 MB"
For repeated formatting, always cache an Intl.NumberFormat:
// ❌ Slow — creates a new formatter for every value
items.map(x => x.toLocaleString("en", { style: "currency", currency: "USD" }));
// ✅ Fast — reuse one formatter
const fmt = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
});
items.map(x => fmt.format(x));
Static Methods on Number
These live on Number itself, not on instances. They’re the modern, strict versions.
| Static | What It Does |
|---|---|
Number.isInteger(x) |
True only for integers |
Number.isFinite(x) |
True for real numbers (not Infinity or NaN) |
Number.isNaN(x) |
True only for NaN — no coercion |
Number.isSafeInteger(x) |
True if integer within ±(2⁵³−1) |
Number.parseInt(s, radix) |
Same as global parseInt |
Number.parseFloat(s) |
Same as global parseFloat |
Number.EPSILON |
Smallest 1 + ε ≠ 1 |
Number.MAX_SAFE_INTEGER |
2⁵³ − 1 |
Number.MAX_VALUE |
Largest representable float |
Number.MIN_VALUE |
Smallest positive float |
Number.POSITIVE_INFINITY |
Infinity |
Number.NEGATIVE_INFINITY |
-Infinity |
Number.NaN |
NaN |
Number.isInteger(42) // true
Number.isInteger(42.0) // true (no decimal part)
Number.isInteger(42.5) // false
Number.isInteger("42") // false ← strict — string is not a number
Number.isFinite(1) // true
Number.isFinite(Infinity) // false
Number.isFinite(NaN) // false
Number.isFinite("42") // false ← strict, no coercion
Number.isNaN(NaN) // true
Number.isNaN("hi") // false ← strict
Number.isNaN(undefined) // false
Number.isSafeInteger(2 ** 53 - 1) // true
Number.isSafeInteger(2 ** 53) // false
Global isNaN, isFinite, parseInt, parseFloat (Legacy)
Older, more coercive versions:
// Globals coerce to number first — usually misleading
isNaN("hello") // true — "hello" coerces to NaN
isNaN(undefined) // true
isNaN("42") // false — "42" coerces to 42
isFinite("42") // true — coerces
Number.isNaN("hello") // false ← strict, no coercion
Number.isNaN(NaN) // true
| Use | Don’t Use |
|---|---|
Number.isNaN(x) |
isNaN(x) |
Number.isFinite(x) |
isFinite(x) |
Number.parseInt(x, 10) |
parseInt(x, 10) (still works but global) |
parseInt quirks worth remembering:
parseInt("42") // 42
parseInt("42px") // 42 ← strips trailing junk
parseInt("0x10") // 16 ← recognises 0x prefix
parseInt("10", 2) // 2 ← binary
parseInt("10", 16) // 16 ← hex
parseInt("", 10) // NaN
parseInt("abc", 10) // NaN
// ❌ Without radix, old engines treated "08" as octal
parseInt("08") // 8 in modern engines, but ALWAYS pass radix
parseInt("08", 10) // 8
parseFloat("3.14") // 3.14
parseFloat("3.14abc") // 3.14
parseFloat("abc") // NaN
parseFloat("1e3") // 1000
Tip: Always pass parseInt(s, 10). It’s a one-character habit that prevents the most embarrassing JS bug.
The Math Object — Most-Used Helpers
Full chapter is 23. The everyday subset:
Math.abs(-7) // 7
Math.sign(-5) // -1
Math.sign(0) // 0
Math.sign(5) // 1
Math.round(2.5) // 3
Math.round(-2.5) // -2 ← rounds toward +∞
Math.floor(2.9) // 2
Math.ceil(2.1) // 3
Math.trunc(-2.9) // -2 ← chops decimal
Math.min(3, 1, 2) // 1
Math.max(3, 1, 2) // 3
Math.min(...arr) // spread to apply to array
Math.sqrt(81) // 9
Math.cbrt(27) // 3
Math.pow(2, 10) // 1024 (use 2 ** 10 instead)
Math.hypot(3, 4) // 5 sqrt(3² + 4²)
Math.log(Math.E) // 1
Math.log2(1024) // 10
Math.log10(1000) // 3
Math.random() // 0 ≤ x < 1
Random Integer Pattern
function randInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
randInt(1, 6); // 1..6
randInt(0, 99); // 0..99
Converting To/From Numbers — Cheatsheet
// String → Number
Number("42") // 42
+("42") // 42
parseInt("42px", 10) // 42
parseFloat("3.14") // 3.14
// Number → String
(42).toString() // "42"
String(42) // "42"
`${42}` // "42"
42 + "" // "42" (works but ugly)
(255).toString(16) // "ff"
// Number → Boolean
Boolean(0) // false
Boolean(42) // true
!!42 // true
// Boolean → Number
Number(true) // 1
+true // 1
A Realistic Example — Safe Number Parser
/**
* Strict parser: returns a number, or null for any non-numeric input.
*/
function parseNumeric(input, { min, max, integer = false } = {}) {
const n = Number(input);
if (!Number.isFinite(n)) return null;
if (integer && !Number.isInteger(n)) return null;
if (min !== undefined && n < min) return null;
if (max !== undefined && n > max) return null;
return n;
}
parseNumeric("42"); // 42
parseNumeric("3.14"); // 3.14
parseNumeric("3.14", { integer: true }); // null
parseNumeric("42", { min: 0, max: 100 }); // 42
parseNumeric("200", { min: 0, max: 100 }); // null
parseNumeric("abc"); // null
parseNumeric(""); // null ← Number("") is 0, but isFinite(0) is true... let's recheck
Wait — Number("") is actually 0, and 0 is finite. If you want empty string to fail:
function parseNumeric(input, opts = {}) {
if (typeof input === "string" && input.trim() === "") return null;
// ... rest as above
}
This is exactly why writing a strict parser takes more lines than you’d expect — JavaScript’s coercion has corners everywhere.
Common Mistakes
// ❌ toFixed returns a string, used as a number
const total = (price * 3).toFixed(2);
sum += total; // "9.00" + "9.00" → "9.009.00"
// ✅
sum += Number((price * 3).toFixed(2));
// ❌ Global isNaN
isNaN("hello"); // true — confusing!
// ✅
Number.isNaN(value); // strict
// ❌ parseInt without radix
parseInt("08"); // Usually 8, but historically risky
// ✅
parseInt("08", 10);
// ❌ Math.round for halves
Math.round(-0.5); // 0 ← rounds toward +∞ (away from -∞)
Math.round(0.5); // 1
// Use Math.trunc when you specifically want to chop
Best Practices Checklist
- ✅ Prefer
Number.isNaN,Number.isFinite,Number.isIntegerover globals - ✅ Always pass radix to
parseInt - ✅ Cache
Intl.NumberFormatinstances when formatting many values - ✅ Convert
toFixedoutput back to number if you’ll do math on it - ✅ Use
Number.isSafeIntegerbefore trusting large integer IDs - ❌ Don’t use legacy globals (
isNaN,isFinite) — they coerce silently - ❌ Don’t compare floats with
===aftertoFixed(compare numbers with epsilon instead) - ❌ Don’t use
Math.roundif you specifically want banker’s rounding — it doesn’t
What’s Next?
Strings and numbers covered. Now the workhorse collection type: arrays. We’ll create them, mutate them, destructure them, and meet the iteration methods that make modern JavaScript so expressive.