How to Parse Numbers in JavaScript
When you read a value from a form field, a URL parameter, or a JSON API response, it almost always arrives as a string. Before you can do any math with it, you need to convert it to a number. JavaScript gives you several ways to do that, and they behave differently enough that choosing the wrong one causes subtle bugs. This article covers the main methods, when to use each, and the edge cases that trip developers up most often.
Key Takeaways
parseInt()andparseFloat()perform partial parsing, reading left to right and stopping at the first invalid character — useful for strings like"24px".Number()and unary+require the entire string to be valid, returningNaNotherwise — ideal for strict conversions from API data.- Always pass the radix to
parseInt()and always validate results withNumber.isNaN()rather than the globalisNaN(). - Use
BigInt()for integers beyondNumber.MAX_SAFE_INTEGER, and normalize locale-formatted strings before parsing.
Quick Comparison: JavaScript String-to-Number Conversion Methods
| Method | Input "42px" | Input "3.14" | Input "" | Input "abc" |
|---|---|---|---|---|
parseInt("42px", 10) | 42 | 3 | NaN | NaN |
parseFloat("42px") | 42 | 3.14 | NaN | NaN |
Number("42px") | NaN | 3.14 | 0 | NaN |
+"42px" | NaN | 3.14 | 0 | NaN |
parseInt(): Partial Parsing for Integers
parseInt(string, radix) reads characters left to right and stops the moment it hits something it cannot parse. That makes it useful for strings like "24px" or "10rem", where the number comes first.
parseInt("24px", 10) // 24
parseInt("3.99", 10) // 3 (decimal point stops parsing)
parseInt("abc", 10) // NaN (first character is invalid)
Always pass the radix. Without it, parseInt treats strings starting with 0x as hexadecimal and otherwise parses in base 10. While modern engines default to base 10, omitting the radix is a well-known source of bugs and makes your intent unclear.
parseInt("0xFF", 16) // 255 — explicit hex parsing
parseInt("011", 10) // 11 — radix prevents ambiguity
One non-obvious behavior: parseInt stops at the decimal point in "6.022e23", so parseInt("6.022e23", 10) returns 6, not 602200000000000000000000. Do not use parseInt to truncate large floating-point numbers. Use Math.trunc() instead.
parseFloat(): Partial Parsing for Decimals
parseFloat() works the same way as parseInt but preserves the decimal portion. It has no radix parameter and always parses in base 10.
parseFloat("3.14rem") // 3.14
parseFloat("1e3") // 1000 — understands scientific notation
parseFloat("px10") // NaN — first character is invalid
Use parseFloat when the input may contain a decimal value and you want to preserve it.
Number() and Unary +: Strict Conversion
Both Number() and the unary + operator require the entire string to be a valid number. If any part of it is not, you get NaN. That strictness is an advantage when working with API responses or validated form data, where a partial parse would be a silent error.
Number("42") // 42
Number("3.14") // 3.14
Number("42px") // NaN — stricter than parseInt
Number("") // 0 — watch out for this
+"42" // 42 — identical behavior, shorter syntax
The empty-string edge case matters in form handling. Number("") returns 0, not NaN, which can mask a missing value. Always check for empty input before converting.
Discover how at OpenReplay.com.
Numeric Separators Do Not Work at Runtime
JavaScript source code allows 1_000_000 as a numeric literal, but that syntax does not carry over to string parsing.
parseInt("1_000", 10) // 1 — parsing stops at the underscore
Number("1_000") // NaN
If your API or user input uses underscores as thousand separators, strip them first with str.replace(/_/g, "").
BigInt(): Parsing Large Integers
JavaScript’s Number type loses precision beyond Number.MAX_SAFE_INTEGER (2⁵³ − 1). For values larger than that — database IDs, cryptographic values, financial integers — use BigInt().
BigInt("9007199254740993") // 9007199254740993n — exact
Number("9007199254740993") // 9007199254740992 — off by one
Pass the string directly to BigInt(). Do not pass it through parseInt first, because precision is already lost at that point. Note that BigInt values cannot be mixed with regular Number values in arithmetic without explicit conversion.
Locale-Aware Parsing
JavaScript has no built-in function to parse locale-formatted numbers like "1.234,56" (common in German or Spanish locales). You need to normalize the string manually before parsing:
const raw = "1.234,56"
const normalized = raw.replace(/\./g, "").replace(",", ".")
parseFloat(normalized) // 1234.56
Which Method Should You Use?
- User input or CSS values with units →
parseInt(str, 10)orparseFloat() - API responses or strictly validated data →
Number()or unary+ - Integers beyond 2⁵³ − 1 →
BigInt() - Always validate that the result is not
NaNbefore using it:
const qty = parseInt(input, 10)
if (Number.isNaN(qty)) {
// handle invalid input
}
Use Number.isNaN(), not the global isNaN(). The global version coerces its argument first, which means isNaN("") returns false even though "" is not a number.
Conclusion
The right JavaScript number-parsing method depends on what you know about your input. Use parseInt or parseFloat when partial parsing is acceptable and expected. Use Number() or unary + when the entire string must be a valid number. Reach for BigInt() when precision matters for large integers. In all cases, check for NaN before you use the result.
FAQs
parseInt reads a string left to right and stops at the first character it cannot interpret as part of an integer. Number requires the entire string to be a valid numeric value. For example, parseInt of 42px returns 42, while Number of 42px returns NaN. Use parseInt for partial parsing and Number for strict conversion.
The ECMAScript specification defines an empty string as converting to 0 when passed to Number or the unary plus operator. This can mask missing form values. Always check whether the input string is empty before converting it to a number to avoid treating blank fields as zero.
Use BigInt when the integer exceeds Number.MAX_SAFE_INTEGER, which is 2 to the power of 53 minus 1. Beyond that threshold, Number loses precision and may silently round values. Pass the numeric string directly to BigInt rather than converting through parseInt or Number first, since precision is lost during that intermediate step.
The global isNaN coerces its argument to a number before checking, which produces misleading results. For instance, isNaN of an empty string returns false because the empty string coerces to 0. Number.isNaN skips coercion and only returns true if the value is literally NaN, making it the reliable choice for validation.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.