How to Convert a String to a Number in JavaScript? Integers, Floats, Big Numbers, and Edge Cases Explained.
This article is a deep dive into the wacky world of number conversion in JavaScript. (And it only scratches the surface.) The method you’ll use will greatly depend on the type of data you’re working with. For example:
- Are these just integers or can they be decimal (float) numbers?
- How big can these numbers be? How small can they be?
- Are they base 10 (decimal) numbers, or are you dealing with a different base like hexadecimal?
- What about
Infinity
? How do you want to handleNaN
? - What about different formatting types based on language?
The Number Constructor
Just providing the string to the Number
constructor might be enough for your use case. Examples:
Number("123") // => 123
Number("-123") // => -123
Number("123.45") // => 123.45 (floating point number)
Number("12e5") // => 1200000
Number("0.12e-5") // => 0.0000012
Number("Infinity") // => Infinity
But there’s also some interesting edge cases:
Number("12e") // => NaN
Number("123,000") // => NaN
Number("") // => 0 (this one is very dangerous!)
This method is attractive because of the versitility, but also very dangerous. Be sure to cover your code with unit tests so edge cases don’t slip through!
Using parseInt
and Handling Different Bases (Radix)
parseInt
is a built-in JavaScript function that parses a string argument and returns an integer of the specified base (radix). If you know you are only dealing with integers, this is your best best.
parseInt("123") // => 123
parseInt("-123") // => -123
The method has a second parameter, which is 10
by default, indicating that the conversion should be base 10. But you can change this:
parseInt("fff", 16) // => 4095
parseInt("0101", 2) // => 5
Things that are not integers, will end up being converted to NaN
:
parseInt("Infinity") // => NaN
parseInt("") // => NaN
But you should be aware of these edge cases:
parseInt("123.45") // => 123
parseInt("123,000") // => 123
parseInt("12e5") // => 12
Making Floats with parseFloat
I hope that whatever you’re doing with floats is managable, because these can become quite a nightmare. Here’s some examples of what you can expect:
parseFloat("123") // => 123
parseFloat("-123") // => -123
parseFloat("123.300") // => 123.3
parseFloat("12e5") // => 1200000
parseFloat("12e-5") // => 0.00012
parseFloat("123,300") // => 123
parseFloat("123,300.00") // => 123
parseFloat("Infinity") // => Infinity
paeseFloat("") // => NaN
Two questions arise here:
- What is the level of precision?
- How do you handle different locales? Some might format the number
123456
as123,456.00
and others123.456,00
, depending on the country.
Precision and toPrecision
As you may have figured out by now all JavaScript numbers are the same Number
type. There is no special float
data type. All numbers are internally stored in double-precision 64-bit binary format IEEE 754. (Just like double
in Java or C#.) The Number
type keeps 17
decimal places of precision. The largest value a Number can hold is about 2^53 -1
. This value is represented by the constant Number.MAX_SAFE_INTEGER
. (Another lie, since it’s not actually an integer.) You can check this yourself:
Math.pow(2, 53) - 1 === Number.MAX_SAFE_INTEGER // => true
If you need to format your number to a set precission, the toPrecision
method is there:
const a = 123.456
console.log(a.toPrecision(10)) // => "123.4560000"
Different Locales
Unfortunetly, there is no built-in way to distinguish between different locales when it comes to parsing numbers. You will have to look in userland for libraries that accomplish this task.
BigInt
Need to represent really, really big numbers? You can use the BigInt
object or just append n
to an integer to cast it into this type. Examples:
const hugeNum1 = BigInt("904240240249024902094290407199254740991");
const hugeNum2 = 904240240249024902094290407199254740991n;
hugeNum1 === hugeNum2 // => true
typeof hugeNum1 === 'bigint' && typeof hugeNum2 === 'bigint' // => true
BigInt Comparison and Equality
But also note that there some interesting things when trying to compare BigInt with numbers. For example, strict equality comparison will fail, while loose comparison can succeed:
const num = 0;
const bigNum = 0n;
num1 === bigNum // => false, they are not of the same type!
num == bigNum // => true, once cast to the same type their values are equal
Other comparison operations work as expected:
0n < 1 // true
1n > 0 // true
2n > 2 // false
2n < 2 // false
BigInt and Sorting
Since the above operations work as expected, it is possible to sort an array of BitInts using the default behaviour of Array.sort
. It’s also possible to sort a mixed array of numbers and BigInts!
const mixed = [4n, 6, -10n, 10, 4, 0, 0n]
mixed.sort() // default sorting behavior
// => [ -10n, 0, 0n, 10, 4n, 4, 6 ]
But as you might see, this is not the type of sorting you were perhaps expecting. This is because the default sort does not compare the numbers by value. Instead, the the default sort order is ascending and based upon converting the elements into strings, then comparing their sequences of UTF-16 code values.
So the usual way to sort numbers by value is to provide a custom sort function, like this:
const mixed = [10, 2, -1, 0, 6];
mixed.sort((a, b) => a - b);
// => [ -1, 0, 2, 6, 10 ]
But this won’t worked with our mixed array:
const mixed = [4n, 6, -10n, 10, 4, 0, 0n]
mixed.sort((a, b) => a - b);
// => Uncaught TypeError: can't convert BigInt to number
BigInt Operation
You can perform regular operations such as +
, -
, *
, **
and %
between two BigInts, but you cannot mix them with regular numbers. If you’re dealing with BigInts, then cast every operand into a BigInt to ensure there is no loss of precision or runtime error.
BigDecimal
Sadly, this type does not exist in JavaScript and you’ll have to look into userland solutions to find a library that fits your needs.
Summary
I’d suggest using the option that fits the use case the best and thoroughly testing your data transformation code with unit tests. For me this is usually parseInt
as integers are usually what I’m working with in my web apps. Even if what you need is decimal, you can think about repesenting it as an integer.
For, example $9.99
can be stored internally as 999
cents and formatted as 9.99
on the UI.
Be careful to account for the possibility of NaN
or Infinity
and handling such errors gracefully!
Comments ()