Coercion is JavaScript converting types behind your back. Conversion is you doing it on purpose, with a function that makes your intent obvious to anyone reading the code. This lesson is the complete toolkit: strings to numbers, numbers to strings, dates, booleans, and the full table of what every value turns into.
Number() converts the whole string or nothing. Spaces around the number are allowed; anything else makes it NaN:
console.log(Number("3.14"), Number(Math.PI));
console.log(Number(" 42 "), Number(""), Number(" "));
console.log(Number("0x1F"), Number("1e3"), Number("-5"));
console.log(Number("99 88"), Number("John"), Number("12px"));
Number("") and Number(" ") are 0, not NaN. A blank form field silently becomes zero. Check for blank text before converting.
These read from the start of the string and stop at the first character that does not fit. parseInt also drops any decimals:
console.log(parseInt("42px"), parseFloat("3.14abc"));
console.log(parseInt("3.99"), parseInt(" 7 days"));
console.log(parseInt("px42"), parseInt("")); // must START with a number
console.log(parseInt("101", 2), parseInt("ff", 16)); // optional base
| Text | Number() | parseInt() | parseFloat() |
|---|---|---|---|
| "42" | 42 | 42 | 42 |
| "42px" | NaN | 42 | 42 |
| "3.99" | 3.99 | 3 | 3.99 |
| "" | 0 | NaN | NaN |
| "abc" | NaN | NaN | NaN |
Number() to validate: it rejects anything that is not entirely a number. Use parseInt / parseFloat to pull a number off the front of text like "42px" or "3.5kg".
parseInt(0.0000005) is 5. The number is first turned into the string "5e-7", and parseInt stops at the e. To round a number, use Math.trunc or Math.floor, not parseInt.
A + in front of a value converts it exactly like Number(). If it cannot, the result is still a number: NaN.
const y = "5";
const x = +y;
console.log(x, typeof x);
const z = +"John";
console.log(z, typeof z);
String() works on any number: a literal, a variable, or an expression. The number method toString() does the same (JS toString()):
const n = 123;
console.log(String(n), String(100 + 23), n.toString(), (100 + 23).toString());
The formatting methods from Number Methods also return strings, rounded the way you choose:
| toFixed(1) | (123.456).toFixed(1) | "123.5" | A set number of decimals |
| toPrecision(4) | (123.456).toPrecision(4) | "123.5" | A set number of significant digits |
| toExponential(2) | (123.456).toExponential(2) | "1.23e+2" | Scientific notation |
Inside, a date is a number: milliseconds since January 1, 1970 (UTC). Number(), getTime(), and unary + all give it to you, and new Date(ms) turns it back:
const d = new Date(Date.UTC(2026, 0, 1));
console.log(Number(d), d.getTime(), +d);
console.log(new Date(0).toISOString());
console.log(new Date(1767225600000).toISOString());
String(new Date()) and new Date().toString() give the long local text you saw in JS toString(). An invalid date converts to NaN: Number(new Date("nope")).
The get methods return numbers. Convert and pad them to build your own format, and remember months start at 0:
const d = new Date(2026, 0, 5, 14, 7);
console.log(d.getMonth(), (d.getMonth() + 1).toString());
console.log(d.getMinutes(), String(d.getMinutes()).padStart(2, "0"));
console.log(d.toLocaleString("en-US", { month: "long" }));
getMinutes() returns "(0-23)." Minutes run from 0 to 59.d = new Date(); with no let or const. That creates an automatic global variable (not recommended, see JS Variables), and in strict mode it is ReferenceError: d is not defined.console.log(Number(false), Number(true));
console.log(String(false), true.toString());
console.log(Boolean(1), Boolean(0), Boolean("0"), Boolean(""));
console.log(BigInt("12"), Number(12n), String(10n ** 20n));
console.log(BigInt(1.5));
A BigInt has no fractions, so a decimal cannot become one. A Symbol cannot become a number at all: Number(Symbol("x")) is TypeError: Cannot convert a Symbol value to a number.
What every common value becomes with Number(), String(), and Boolean(). The rows marked * are the ones that surprise people:
| Value | Number() | String() | Boolean() |
|---|---|---|---|
| false | 0 | "false" | false |
| true | 1 | "true" | true |
| 0 | 0 | "0" | false |
| 1 | 1 | "1" | true |
| "0" * | 0 | "0" | true |
| "000" * | 0 | "000" | true |
| "1" | 1 | "1" | true |
| NaN | NaN | "NaN" | false |
| Infinity | Infinity | "Infinity" | true |
| -Infinity | -Infinity | "-Infinity" | true |
| "" * | 0 | "" | false |
| "20" | 20 | "20" | true |
| "twenty" | NaN | "twenty" | true |
| [ ] * | 0 | "" | true |
| [20] * | 20 | "20" | true |
| [10,20] * | NaN | "10,20" | true |
| ["twenty"] | NaN | "twenty" | true |
| ["ten","twenty"] | NaN | "ten,twenty" | true |
| function(){} | NaN | "function(){}" | true |
| { } * | NaN | "[object Object]" | true |
| null * | 0 | "null" | false |
| undefined * | NaN | "undefined" | false |
Two rules explain most of the table. An array converts through its string: [20] is "20", which is the number 20, but [10,20] is "10,20", which is not a number. And null becomes 0 while undefined becomes NaN.
What does this log?
console.log(Number(""), parseInt(""), Number("12px"), parseInt("12px"));
0 NaN NaN 12. Number treats empty text as 0 but rejects "12px" entirely. parseInt needs at least one digit at the start, and stops at "px".What is Number([10, 20])?
3010"10,20"NaNWhy is parseInt(0.0000005) equal to 5?
parseInt expects a string, so the number is converted to text first: "5e-7". It reads the 5 and stops at the e.Number, parseInt, and parseFloat. Explain each differenceString, and padStart