## DEV Community

EmNudge

Posted on • Updated on

# Converting Strings To Numbers in JS: Subtleties, Secrets, and Slip-ups

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
``````

## 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
``````

## `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:

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.