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.
Related protips:
Written by Jose Jesus Perez Aguinaga
Related protips
5 Responses
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
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'))
.run
async : true
Result
~~~
.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.
Good article!
In the past, I often used "+" to coerce a character string to numeric form. I recently got tripped up by the fact that "+" is overloaded on concatenation in JavaScript, so instead of 1 + 2 = 3, I got 1 + 2 = 12! I think I'll switch to subtracting zero, as it is just as fast, and unambiguous too boot!
Couple things: First you say that parseInt is the fastest, and yet all the data for the jsperf test shows that isn't really the case, ignoring the fact that parseInt is only going to work if you are dealing with values you are sure are integers.
fajny! Zmierzyłem się z tym samym problemem i Twoja odpowiedź mi pomogła