Thomas Fuchs
Hi, I'm Thomas Fuchs. I'm the author of Zepto.js, of script.aculo.us, and I'm a Ruby on Rails core alumnus. With Amy Hoy I'm building cheerful software, like Noko Time Tracking and Every Time Zone and write books like Retinafy.me.
   Want me to speak at your conference? Contact me!

Adventures in JavaScript number parsing

May 12th, 2010

So you want to parse strings and convert them into numbers? JavaScript has the straight-forward parseInt method for this, you say.

parseInt("1") // --> 1

But, sadly, and quite unexpectedly, it’s not that straight-forward. Consider:

parseInt("01") // --> 1
parseInt("02") // --> 2
parseInt("07") // --> 7
parseInt("08") // --> 0  WTF?
parseInt("09") // --> 0  WTF?

parseInt thinks the numbers that are preceded by a “0” are octal numbers (in the octal numeral system only the digits 0 to 7 are used).

There’s a nice way to work around this, and also some more hackish methods. First off, let’s have a look at the “proper” way of fixing this issue:

parseInt("07", 10) // --> 7
parseInt("08", 10) // --> 8
parseInt("09", 10) // --> 9

The second argument to parseInt is a Radix to be used for the conversion of the string into a number. A radix of 10 means, use the decimal numeral system, which is probably what you want (the decimal system is also called “base ten”).

Some of you might strike this as quite verbose, and indeed, most other programming languages basically assume base 10, and let you specifically override the radix in case you really need to use that base 13 or base 7 numeral system. You can work around the verbosity and actually have a little bit of a performance optimization at the same time by coercing the string into a number, by applying an operator that requires numerical arguments.

Here is one way to make this shorter, and avoid the call to parseInt altogether:

// unary + operator 
+"08"  // -> 8 

Though short and concise, the unary + operator might not always be a good choice, especially if you do calculations or string concatenation. You can use a double binary negation instead:

// unary + requires parenthesis
"test" + (+"08")  // -> "test8" 

// double binary negation
"test" + ~~"08"  // -> "test8" 

Be aware that while the unary + operator works with floating point numbers too, applying binary operators like the double negation will also cut off the fractional part of your number:

+"1.2"  // -> 1.2
~~"1.2" // -> 1
~~"-1.2" // -> -1
// note: ~~ with negative numbers behaves differently from Math.floor
// Math.floor(-1.2) // -> -2

This can be used if you quickly want to convert a number that’s provided in a string and also cut off the fractional part (equivalent to rounding down for positive numbers).

If you need to optimize iterative algorithms, these optimizations can really help bringing down code size and as a side effect avoid expensive function calls (but please never ever optimize without a reason!).