Number.prototype.toString()
Converts a number to a string, optionally in any base from 2 to 36.
toString()
toString(radix)Parameters
| Parameter | Type | Description |
|---|---|---|
$radixoptional | number= 10 | An integer base between 2 and 36 to represent the number in. Digits above 9 use the letters a–z. |
Return value
stringA string representing the number in the given base. When radix is 10, scientific notation is used if the magnitude is 10^21 or greater, or less than 10^-6.
Errors
Throws a RangeError if radix is less than 2 or greater than 36, and a TypeError if called on a value that is not a number.
Called with no argument this is the conversion that already happens implicitly in template literals and string concatenation, so you rarely need to write it. The reason to call it explicitly is the radix: (255).toString(16) is "ff", (5).toString(2) is "101". It is the inverse of parseInt() with the same base.
Negative numbers are not two's complement
This surprises people coming from C. (-10).toString(2) is "-1010" — a minus sign followed by the magnitude, not a bit pattern. If you want the 32-bit two's-complement representation, force the value through a bitwise operator first: (-10 >>> 0).toString(2).
Fractions and big values
Non-integers are supported in any base: (0.5).toString(2) is "0.1". In base 10, magnitudes at or above 1021 or below 10-6 come back in exponential form — (1e21).toString() is "1e+21" — which will break a naive string parser downstream.
When to reach for it
Hex colour values, bitmask debugging, compact base-36 identifiers, and any place you need to see the raw bits of a flag word. Pad the result yourself with padStart(); toString() never adds leading zeros.
Example
When to use it
- Print a bitmask in binary while debugging flag logic
- Convert an RGB component to a two-character hex string
- Generate a short base-36 identifier from a counter
Frequently asked questions
How do I convert a number to binary in JavaScript?
Call n.toString(2). For negative values use (n >>> 0).toString(2) to get the 32-bit two's-complement pattern instead of a signed "-1010" style string.
Why does toString() give me "1e+21" instead of digits?
In base 10, magnitudes at or above 1e21 and below 1e-6 are rendered in exponential notation. Use toFixed() or BigInt for large integers you need in full decimal form.
What is the maximum radix toString() accepts?
36, using digits 0-9 then letters a-z. Anything below 2 or above 36 throws a RangeError.
More examples
Building a hex colour string
toString(16) drops leading zeros, so padStart(2, '0') is mandatory — without it, a component of 0 would collapse the string to four characters.
function rgbToHex(r, g, b) {
return '#' + [r, g, b]
.map((c) => c.toString(16).padStart(2, '0'))
.join('');
}
console.log(rgbToHex(255, 128, 0)); // "#ff8000"
console.log(rgbToHex(0, 0, 0)); // "#000000"
console.log(rgbToHex(18, 52, 86)); // "#123456"Round-tripping with parseInt
Every base round-trips exactly for integers, which is what makes base 36 a safe compact encoding for numeric ids.
const n = 1234567;
for (const radix of [2, 8, 16, 36]) {
const s = n.toString(radix);
console.log(radix, s, Number.parseInt(s, radix) === n);
}
// 2 "100101101011010000111" true
// 8 "4553207" true
// 16 "12d687" true
// 36 "qglj" trueWhere base 10 changes shape
The switch to exponential form happens at 1e21 and below 1e-6, so string handling that assumes plain digits needs a guard at those boundaries.
console.log((1e20).toString()); // "100000000000000000000"
console.log((1e21).toString()); // "1e+21"
console.log((0.000001).toString()); // "0.000001"
console.log((0.0000001).toString()); // "1e-7"
try {
(255).toString(37);
} catch (err) {
console.log(err.name); // "RangeError"
}
Discussion