In every programmer's life there comes a time when they must extract a number from a string.
*sniff* They grow up so fast...
In Javascript we don't typecast, but use functions (usually). We're going to go over a few different methods and explain them a bit more in depth.
Number()
- conversion using the Number class
This is probably a good default to rely on if you're unsure which one to use. Passing any string containing non-numeric values will return a NaN
.
console.log(Number("4")); // 4
console.log(Number("4.01")); // 4.01
console.log(Number("42 g")); // NaN
Note that this returns a different result than new Number()
.
const myNum1 = Number("4");
console.log(myNum1); // 4
console.log(myNum1 === 4); // true
console.log(myNum1 == 4); // true
const myNum2 = new Number("4");
console.log(myNum2); // Number {4}
console.log(myNum2 === 4); // false
console.log(myNum2 == 4); // true
You can find more info on the MDN page.
Unary +
Operator - conversion using +
Passing any string containing non-numeric values will return a NaN
.
console.log(+"4"); // 4
console.log(+"4.01"); // 4.01
console.log(+"42 g"); // NaN
This is not the same as the binary +
operator. Same symbol, different context. Here's an example.
const myNum = "4";
console.log(+myNum); // 4
console.log(0 + myNum); // "04"
When adding a number with a string using the binary +
operator, it will be coerced into a string. No, the spaces and order does not matter by the second example. Without a first parameter, the +
changes to a unary operator and acts differently. This is obviously some very confusing and nuanced behavior.
parseInt()
- conversion to int
parseInt()
is a part of both the window
object and Number
object. This means it can either be used as parseInt()
or Number.parseInt()
.
Passing it a string representation of a number, it will return an integer version.
parseInt()
can also be passed a second parameter - the radix. This number describes in which base to process the number. e.g. Base 16, base 8, base 10, etc.
console.log(parseInt('0xF', 16)); // 15
console.log(parseInt('1111', 2)); // 15
console.log(parseInt(10, 10)); // 15
Its default is base 10 in most instances, but it is highly recommended to add it in regardless since leaving it out can lead to accidents. Google Apps Script, a pre-ES6 JS-like language used for dev work on the G Suite platform, defaults to octal if it has a leading 0. This is mostly for pre-ECMAscript 5, but it is still encouraged to include a radix.
One of the other reasons to use parseInt()
over the alternatives is how it parses strings which include non-numeric characters. It will parse until it hits a non-numeric character and then stop. If it starts with a non-numeric character, it will return NaN
.
console.log(parseInt("4 aliens", 10)); // 4
console.log(parseInt("831million", 10)); // 831
console.log(parseInt("327 * 31", 10)); // 327
console.log(parseInt(".391", 10)); // NaN
Note: Due to this, unlike all other options, it cannot parse "3.230e+2"
as 323
. It will return 3
.
This is incredibly useful for parsing CSS unit values. These usually include a number and then some unit type i.e. "150px", "20deg", "15rem", etc.
// getting the css width of a tag with the class of "box"
const boxWidth = document.querySelector('.box').style.width;
console.log(boxWidth); // 24px
console.log(parseInt(boxWidth, 10)); // 24
console.log(Number(boxWidth)); // NaN
You can find more info on the MDN page
parseFloat()
- conversion with decimals
parseFloat()
is a part of both the window
object and Number
object. This means it can either be used as parseFloat()
or Number.parseFloat()
.
If the string does not contain a decimal, parseFloat()
will not add one. It simply preserves them if there are any present.
Additionally, parseFloat()
does not provide a radix option. What is the difference between parseFloat()
and number then? parseFloat()
also does not provide a NaN
when a non-numeric character is present in the string (and is not the first character).
console.log(parseFloat("4.5 pizzas left", 10)); // 4.5
console.log(parseFloat("3.230e+2", 10)); // 323
console.log(parseFloat("830.2 * 31.4", 10)); // 327.01
console.log(parseFloat(".391", 10)); // 0.391
console.log(parseFloat("one3.1", 10)); // NaN
Math
Methods - convert accidentally
The Math
object contains many useful math-related functions. These functions also have a side-effect of converting non-numeric inputs as if it were using Number()
or the unary +
operator.
I will use Math.pow(x, 1)
in the examples, but it is the same across all Math methods.
console.log(Math.pow("32.5", 1)); // 32.5
console.log(Math.pow(".325", 1)); // 0.325
console.log(Math.pow("21 a", 1)); // NaN
This isn't preferable in any context. Unless of course your code's very purpose is to confuse the reader.
Unary ~
Operator - bitwise unary conversion
The unary ~
operator is a bitwise NOT operator. We're converting a base 10 number to base 2 and then converting back. Being a bitwise operator, any number is also cast to an integer, either through truncation or otherwise (I'm not quite sure of the method).
A bitwise NOT operator will flip all the bits. This results in a number represented by -1 * (n + 1)
(assuming n is an integer). Repeating the same operation twice results in the original number.
console.log(~4); // -5
console.log(~~4); // 4
console.log(~~4.311); // 4
While many quote a performance improvement over Math.floor()
and use this instead, this operator can also be used to convert strings to integers in a similar way to parseInt()
.
console.log(~"4"); // -5
console.log(~~"4"); // 4
console.log(~~"4.311"); // 4
A major difference here, however, is that it will never return NaN. If the string is non-numeric or contains non-numeric characters, it will return -1
. Preforming the operation again will preform a bitwise NOT on -1
, resulting in 0
.
console.log(~"hat"); // -1
console.log(~~"hat"); // 0
console.log(~~"h4"); // 0
console.log(~~"4h"); // 0
Binary Bitwise Operators - conversion using bitwise binary
There are other bitwise methods we can use as well. While ~
is the only unary bitwise operator, we can use binary bitwise operators and pass useless values to the second operand.
console.log("4"|0); // 4
console.log("4"&-1); // 4
console.log("4"<<0); // 4
console.log("4">>0); // 4
console.log("4">>>0); // 4
This way we're not really doing anything except for parsing it to an integer. Theoretically it should be faster than ~~
, but that's not exactly what we're going to see.
Find out more about Bitwise Operators Here.
Performance Testing
A lot of people are against performance testing. Sometimes specifics are hidden behind the engine in ways where our benchmarking tests will fail to provide accurate results. Tom Dale has a fantastic example over on his blog.
Regardless, with that in mind, it's always a fun thing to look at. I'll be using Benchmark.js for these tests. If one option is only slightly higher (% wise) than the other, it's possible it would score lower on later tests.
const num = "3249323242";
+num; // operations: 6378907
~~num; // operations: 6263920
num>>0; // operations: 6256772
num<<0; // operations: 6256384
num&-1; // operations: 6239926
num>>>0; // operations: 6125457
Number(num); // operations: 6076579
num|0; // operations: 5983553
parseFloat(num); // operations: 589328
parseInt(num); // operations: 534935
Math.pow(num); // operations: 485971
We can see that the bitwise operators were much faster than parseInt()
, but only an insignificant amount faster than Number()
. Number()
is much easier to understand for your colleagues and future self, so be kind.
When To Use What
Use parseInt()
for:
- converting a string from one base to another?
- getting a number from a CSS unit string? Use
parseInt
.
Use parseFloat
for:
- getting a number from a CSS string that includes a decimal.
Use Math
methods for:
- confusing your friends.
Use the unary +
operator for:
- compressing/uglifying a JS file as a substitute for
Number()
.
Use the unary and binary bitwise operators for:
- compressing/uglifying a JS file as a substitute for
parseInt(x, 10)
where the radix and cutoff features aren't needed. - highly performance dependent libraries with the above use case.
Use Number
:
- every other time.
TL;DR
Each method does something slightly different. Use Number()
whenever you're unsure. If you want specifics, you're going to have to read the article.
Top comments (0)