- 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 handle
- 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!
parseInt and Handling Different Bases (Radix)
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
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
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
123.456,00, depending on the country.
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"
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.
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
You can perform regular operations such as
% 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.
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.
$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
Infinity and handling such errors gracefully!