Tuesday, February 12th, 2008
The parseInt gotcha
<>p>Guyon Morée has posted the old chesnut parseInt gotcha, so I thought I should put it up here as a quick tip:I was working on some stuff in javascript which involved some date/string parsing when one morning it failed. "That's weird, yesterday it worked fine!"
After some debugging with FireBug I found parseInt() was failing on me.It was the 8th of February and it was failing on "08" as an input string. I opened the FireBug console and entered parseInt("08"), just to be sure I wasn't' getting mad and sure enough, the output was 0. Just as a way of rechecking my sanity I entered parseInt('07') and this did return the correct answer, 7.
So I googled the parseInt function and discovered some funky default behavior, which was flagged as deprecated.
The parseInt takes a second radix parameter. With this you can tell parseInt the base your input is in.All fine, but there are also some prefixes defined, so you can input '0xff' for hexadecimal values. Unfortunately they also thought it would be smart to assign 0 to octal values. So 08 is being intepreted as an octal value.
Even though I think the behavior is error prone, it's even weirder that it returns 0. I believe it should return something like NaN as it is isn't a valid number in the assumed base.
Mike Owens posted the Prototype based '+' mapping to do the work for you:
-
-
['2008', '02', '11', '06', '21', '03'].map(function(v) { return + v });
-
# [2008, 2, 11, 6, 21, 3]
-
Related Content:











“All fine, but there are also some prefixes defined, so you can input ’0xff’ for hexadecimal values. Unfortunately they also thought it would be smart to assign 0 to octal values. So 08 is being intepreted as an octal value.”
So, who will tell this guy that 0# is considered an octal number in almost every modern language?
Seriously ?!
Don’t people know their basic basis and how to read a spec these days ?
And suggesting that parseInt( ’08′ ); should return NaN is ludicrous.
That is just one of the traps you can avoid using jslint. I listed some more hints on how to understand jslint here: http://wolfram.kriesing.de/blog/index.php/2007/understanding-jslint-output
I don’t see why in the whole article there is not a single code example of how to do it properly (also jslint complains about leaving out the second param btw):
parseInt(myStringThatMightStartWithZeroButStillIsDecimal, 10)Just always use it like that and be happy.
parseDec(i) { return parseInt(i,10) }and you are all happyThank you. The simplest things are sometimes the most difficult ones to remember.
I know, cross-browser testing is out … I checked it on Firefox 2, IE7, Safari 3 Beta and Opera 9, all on Windows. They all returned 0, except Opera. Adding 10 as 2nd parameter to parseInt() returned the correct result in all 4 browsers.
Mathieu: I don’t see how NaN would be more ludicrous than 0 or 10. Other than that, yes, passing the radix argument is _the_ solution.
NaN is a well-defined concept from floating point arithmetic. Since parseInt is supposed to return an integer, it therefore shouldn’t return NaN.
The reason it COULD return NAN is because 08 is the prefix indicating that the number *following* it is in octal. Since there is *nothing* following it NAN would make sense.
His work around is pretty nice to, I have always used parseInt(foo, 10);
Dion:
You should probably run your code through JSLint (http://jslint.com/). It would have thrown an error about the radix missing.
Considering javascript should be always as natural as possible to use why are we bother with plain old rules like “octal are starting with 0″ ? (which may be an old International Business Machine hack)
Should not be a real ohhh ?
like o12 or 12o
Everyone can live better with the ohhh !
umm… Javascript is perfectly natural here, to the point where you typically shouldn’t resort to using parseInt! String->number coercion was the right solution all along, as the author discovered, and has exactly the behavior he was looking for — whether he used the plus trick or the explicit Number constructor or whatever. No need for fancy toolkits here until you need to iterate. He just shouldn’t have been using parseInt in the first place, which does very specific things which are also in line with the language, but obviously a bit more technical in nature (you might notice that number literals also respect the ohhh prefix!)
But it worked yesterday? unfortunately the only thing that didn’t work was your ability to read the specs.
Just a FYI, the snippet I posted to the gumuz’s blog using Prototype was just an example to show how the + operator responded to a list of date-like base-10 decimal strings. Obviously, there’s nothing Prototype-specific about the + operator.
You can read about it here: Javascript Type-Conversion.
- Mike Owens
Sorry Tim, I lost touch with reality when I saw someone actually blogging his revelation about parseInt(). Indeed parseInt( ’08′ ); should return NaN since 08 is not a valid octal number. :p
aww, if i had known ajaxian would accept any submission I would have submitted my discovery of mozilla’s setTimeout’s extra parameter (the lateness) long ago.
I prefer this “String.prototype.parseInt=function(){return parseInt(this,10)}”
Wow…give the guy a break! He didn’t ask Ajaxian to make out this was some kind of major story. (Ajaxian has a habit of taking the most mundane stuff and giving it a high profile.)
And also, some respondents might do well to follow their own advice and read the spec; on the one hand we’re saying Guyon should read the spec, and in the same breath some people question why
parseInt("08")returns0instead ofNaN, proving that we can all overlook things, not just Guyon.The answer, for those who understandably don’t want to wade through the specs (what are blogs for, after all), is that
parseIntand related functions parse as much as they can from a string and then stop. So to illustrate,parseInt("23 days", 10)will return23, and notNan, because it will find as many base 10 numbers as it can before stopping.This means that the example of
parseInt("08")might as well beparseInt("0banana")for all that it means in octal–the answer is correctly zero.Mark
I agree with MarkBirbeck on this one… Why the harshness? Since when are we all above “learning”?! This post may in fact help quite a few people who may be scratching their heads as to why parseInt doesn’t behave as expected.
Give the hating a break already!
MarkBirbeck: Fair enough. If only the difference of time spent commenting on and stumbling on that parseInt() behavior and writting a blog post about it wasn’t so big.
FrankManno: I don’t see hatred in the comments. Harshness yes but no hatred.
Beside there are thousands of results when searching for parseInt 08 on the net.
To ease the mood, here is another potential gotcha: per ECMAscript 262-3 specification, Array.prototype.sort( [compareFunction] ) is not necessary stable, and therefore should not be assumed to be stable.
@MarkBirbeck: certainly no hatred intended on my part. I hope my comment wasn’t read as anything but constructive criticism. And yes, you give another very good reason why parseInt() is usually overkill and better replaced by coercion, IMO, unless you are doing it specifically because you want the behavior of parsing only the number portion.
@sphivo: wow, that article is a gem. How interesting that coercion takes hex strings but not octal. Plenty of gotchas with either method, I guess.