Last Updated: February 01, 2017
· jjperezaguinaga
Me 180x180

Converting Strings to Number in Javascript: Pitfalls

There are many ways to convert a String to a Number. I can think of at least 5 ways to convert a string into a number!

parseInt(num); // default way (no radix)
parseInt(num, 10); // parseInt with radix (decimal)
parseFloat(num) // floating point
Number(num); // Number constructor
~~num //bitwise not
num / 1 // diving by one
num * 1 // multiplying by one
num - 0 // minus 0
+num // unary operator "+"

Which one to use when? When? Why? This tip is an analysis of each one and it's common pitfalls.

According to a couple benchmarks in JsPerf.com most browsers have optimal response for ParseInt. Although it may be the fastest, here are some common mistakes parseInt does:

parseInt('08') // returns 0 in some old browsers.
parseInt('44.jpg') // returns 44

parseInt: Always use it with a radix = parseInt(num, 10), don't use it if you don't want it to guess from characters.

What about ParseFloat? It's all good if you never handle hexadecimal numbers; for instance:

parseInt(-0xFF) // returns -255
parseInt("-0xFF") // returns -255
parseFloat(-0xFF) // returns -255
parseFloat("-0xFF") // returns 0

(Note, a negative hexadecimal number in a string is a special case that will go funky town in your application if you are parsing it. Make sure to always check for NaN values in your app to avoid surprises)

Plus, it retains the problem as parseInt with characters in the number:

parseFloat('44.jpg') // returns 44

**parseFloat: Be careful with hexadecimal numbers, don't use it if you don't want it to guess from characters."

The next one is Bitwise not (~). You can use that to convert a string to an integer only, but it's not for floating numbers. The good thing about it is that it will return "0" if a character appears.

~~1.23 // returns 1
~~"1.23" // returns 1
~~"23" // returns 23
~~"Hello world" // returns 0

What is it doing? It's "flipping" each bit, also known as the A1 complement of the number. You can use, but be aware that it's storing integers, so don't use it unless you are sure your number ranges between the values of a signed 32 bit integer (this is because in the spec it calls ToInt32).

Bitwise not, use it to ensure input doesn't have a character in it, only for integers

What about Number? Number has the same problem that parse* in a way that it will try to figure it out which number you are giving to it:

Number("023") // returns 23
Number(023) // returns 19

(Note, 023 is ACTUALLY an octal number. No matter what you do, it will return 19; goes the same for hexadecimal ones without double or single quotes)

Number was also one of the slowest outcomes in JsPerf.

Number, pretty much don't use it

The last ones are unary operators.

"1.23" * 1 // returns 1.23
"0xFF" - 0 // returns 255
"0xFF.jpg" / 1 // returns NaN
+"023" // returns 23

Unlike the others, unary operators will be really happy to throw you a NaN value if they see anything funky. They are my favorite way to convert numbers, because anything with a character shouldn't be considered neither 0 or "guessed" according to how many digits it has. I pick most of the time the + operator because is the least confusing one. They don't have the best performance though, although -0 has been giving good results.

Best way to convert string to a number?

Negative hexadecimal numbers are the only ones that break inside a string. Any other number should be first parsed into a String (through + "" for instance) and then parsed to a number with a unary operator or a parseInt with a radix. parseFloat takes advantage of performance, but can give you some numeric values where a NaN is more appropriate.

2 Responses
Add your response


appreciate your post, but with which browser did you do the tests? for me the unary operators and ~~ where roughly 100x faster than the official parse functions

over 1 year ago ·

For comparison with Node 6.8.1, I wrote a benchmark for the following techniques (in coffeescript)

Benchmark = require 'benchmark'
assert = require 'assert'

suite = new Benchmark.Suite

convert = "1234"
suite.add 'parseInt', ->
    assert(parseInt(convert, 10) is 1234)
.add 'Number(x)', ->
    assert(Number(convert) is 1234)
.add '~~convert', ->
    assert((~~convert) is 1234)
.add 'convert|0', ->
    assert((convert|0) is 1234)
.add '+convert', ->
    assert((+convert) is 1234)
.on 'complete', ->
    @map (b) ->
        console.log(" b.hz #{b.hz} b.name #{b.name}")
    console.log('Fastest is ' + @filter('fastest').map('name'))
    async : true

.nvm/versions/node/v6.8.1/bin/node --require coffee-script/register src/liveserv-loader/test/benchmark.coffee
b.hz 62781513.35543358 b.name parseInt
b.hz 71269790.1318596 b.name Number(x)
b.hz 22889466.345643885 b.name ~~convert
b.hz 24447918.3306923 b.name convert|0
b.hz 78516405.25189222 b.name +convert
Fastest is +convert

Process finished with exit code 0

Generally +<string> is fastest, but Number() occassionally comes out on top too.

5 months ago ·