Try executing the following in JavaScript:
parseInt('01'); //equals 1
parseInt('02'); //equals 2
parseInt('03'); //equals 3
parseInt('04'); //equals 4
parseInt('05'); //equals 5
parseInt('06'); //equals 6
parseInt('07'); //equals 7
parseInt('08'); //equals 0 !!
parseInt('09'); //equals 0 !!
I just learned the hard way that JavaScript thinks the leading zero indicates an octal integer, and since there is no "8"
or "9"
in base-8, the function returns zero. Like it or not, this is by design.
What are the workarounds?
Note: For sake of completeness, I'm about to post a solution, but it's a solution that I hate, so please post other/better answers.
Update:
The 5th Edition of the JavaScript standard (ECMA-262) introduces a breaking change that eliminates this behavior. Mozilla has a good write-up.
10 Answers 10
This is a common Javascript gotcha with a simple solution:
Just specify the base, or 'radix', like so:
parseInt('08',10); // 8
You could also use Number:
Number('08'); // 8
-
11Number needs quotes around the 08. Also just be warned, Number('08.123') will produce 8.123 as its output. If you really want an integer, don't use Number (or pattern-match your input to ensure integers only).Jason S– Jason S2009年05月11日 22:22:30 +00:00Commented May 11, 2009 at 22:22
-
3Number(08); gives me 8 in Firefox and IE.Paolo Bergantino– Paolo Bergantino2009年05月11日 22:23:35 +00:00Commented May 11, 2009 at 22:23
-
3it's not part of the ECMAscript standard. I'm testing on JSDB which uses Spidermonkey 1.7 (=Firefox JS engine), and complains "08 is not a legal ECMA-262 octal constant"Jason S– Jason S2009年05月11日 22:25:40 +00:00Commented May 11, 2009 at 22:25
-
5Still, use '08' in quotes. 08 doesn't meet the ECMA-262 standard and isn't guaranteed to succeed w/o warnings and/or errors and/or a particular specified behavior.Jason S– Jason S2009年05月11日 22:52:10 +00:00Commented May 11, 2009 at 22:52
-
Old question, but note that Number is different than parseInt: stackoverflow.com/a/4090577Gary S. Weaver– Gary S. Weaver2017年02月03日 22:51:38 +00:00Commented Feb 3, 2017 at 22:51
If you know your value will be in the signed 32 bit integer range, then ~~x
will do the correct thing in all scenarios.
~~"08" === 8
~~"foobar" === 0
~~(1.99) === 1
~~(-1.99) === -1
If you look up binary not (~
), the spec requires a "ToInt32" conversion for the argument which does the obvious conversion to an Int32 and is specified to coerce NaN
values to zero.
Yes, this is incredibly hackish but is so convenient...
-
3Why two operations when one binary or would suffice?Oleg V. Volkov– Oleg V. Volkov2012年08月07日 17:55:40 +00:00Commented Aug 7, 2012 at 17:55
-
@Oleg, Why would one suffice?Sebastian– Sebastian2013年03月29日 19:16:35 +00:00Commented Mar 29, 2013 at 19:16
-
@Grodriguez, and when 0 in |0 is a string?Oleg V. Volkov– Oleg V. Volkov2014年10月24日 16:29:35 +00:00Commented Oct 24, 2014 at 16:29
-
This whole question is about alternatives to parseInt for converting strings to integers. Thus: always.Grodriguez– Grodriguez2014年10月25日 09:55:23 +00:00Commented Oct 25, 2014 at 9:55
From the parseInt documentation, use the optional radix argument to specify base-10:
parseInt('08', 10); //equals 8
parseInt('09', 10); //equals 9
This strikes me as pedantic, confusing, and verbose (really, an extra argument in every single parseInt?) so I'm hoping there is a Better Way.
-
7if you Don't Like Verbosity then just make your own function that calls the builtin function and fills in the arguments you always keep constant.Jason S– Jason S2009年05月11日 22:20:53 +00:00Commented May 11, 2009 at 22:20
-
3Riiiiiiight, because it's not like every single person on StackOverflow would berate you for writing function parseIntB10. Writing your own wrapper function is a terrible idea for this purpose.Stefan Kendall– Stefan Kendall2009年05月11日 22:36:17 +00:00Commented May 11, 2009 at 22:36
-
2@iftrue: I think you missed my point. I personally don't mind just doing parseInt(someString, 10) everywhere to ensure that I force base 10. The OP appears not to like this approach, so I suggested an alternative, which I wouldn't personally use but perhaps it meets his needs. (this is apparently the thinking behind JQuery: make it convenient by adding extra complexity. I don't use JQuery but many people find it useful.)Jason S– Jason S2009年05月11日 23:26:14 +00:00Commented May 11, 2009 at 23:26
-
6Actually it's really important to wrap
parseInt
for convenient use in functional expressions, likemap
in["7","4","09","5"].map(parseInt);
Map
will pass the index of the element in the array as the second argument, which will be interpreted byparseInt
as the base unless you wrap it.Plynx– Plynx2013年02月24日 07:16:57 +00:00Commented Feb 24, 2013 at 7:16
function parseDecimal(s) { return parseInt(s, 10); }
edit: making your own function, to do what you really want, is just an option if you don't like adding the ",10" all the time to the parseInt() call. It has the disadvantage of being a nonstandard function: more convenient for you if you use it a lot, but perhaps more confusing for others.
Specify the base:
var number = parseInt(s, 10);
-
Wow you guys are fast. I even had my answer on the clipboard. Are you plugged directly into the Internet, Neo-style?Portman– Portman2009年05月11日 22:17:46 +00:00Commented May 11, 2009 at 22:17
-
1Why the devil is it not defaulted to base 10Tom Gullen– Tom Gullen2010年08月21日 10:08:41 +00:00Commented Aug 21, 2010 at 10:08
-
2Maybe because it's not primarily meant as a String->Number converting function, but a function that reads a Number from a base b number String.wnrph– wnrph2010年11月16日 22:13:39 +00:00Commented Nov 16, 2010 at 22:13
-
3it is defaulted to base 10 but leading zeros are a widespread way to indicate octal.Nathan– Nathan2010年12月08日 22:09:51 +00:00Commented Dec 8, 2010 at 22:09
Would it be very naughty to replace parseInt with a version that assumes decimal if it has no second parameter? (note - not tested)
parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}
-
2yes, that would be naughty -- it would break other code that relied on the standard behavior.jes5199– jes51992009年10月03日 22:53:22 +00:00Commented Oct 3, 2009 at 22:53
-
4That is true, but there isn't much of that. It also isn't standard behaviour - octal support is optional.Andrew Duffy– Andrew Duffy2009年10月05日 10:14:08 +00:00Commented Oct 5, 2009 at 10:14
-
3But you're also dropping hex support which isn't optional, is it? This should always be true:
parseInt("0xFFFFFF") === 16777215
, but with your naughty hack in place it no longer worksparseInt("0xFFFFFF") === 0
Timo– Timo2013年11月06日 16:23:24 +00:00Commented Nov 6, 2013 at 16:23 -
2@jes5199 But then ECMAScript 5 decided to break other code that relied on that behaviorPiyin– Piyin2018年01月23日 21:24:10 +00:00Commented Jan 23, 2018 at 21:24
You may also, instead of using parseFloat or parseInt, use the unary operator (+).
+"01"
// => 1
+"02"
// => 2
+"03"
// => 3
+"04"
// => 4
+"05"
// => 5
+"06"
// => 6
+"07"
// => 7
+"08"
// => 8
+"09"
// => 9
and for good measure
+"09.09"
// => 9.09
The unary plus operator precedes its operand and evaluates to its operand but attempts to convert it into a number, if it isn't already. Although unary negation (-) also can convert non-numbers, unary plus is the fastest and preferred way of converting something into a number, because it does not perform any other operations on the number.
How about this for decimal:
('09'-0) === 9 // true
('009'-0) === 9 // true
This issue cannot be replicated in (削除) latest* (削除ここまで) Chrome or Firefox (2019).
Test:
console.log(parseInt('08'));
*"Since (ECMAScript 5) JavaScript has abandoned this behaviour, but you should still specify the radix to satisfy older browsers." Source
-
2Yeah, looks like someone finally decided the octal stuff caused more problems than it solved. Though would hate to be one of the 0.01% of people who actually used/relied upon the feature where anything with a leading
0
would parse as octal. :)aroth– aroth2020年09月02日 05:26:39 +00:00Commented Sep 2, 2020 at 5:26 -
2That's going to cause some really nasty bugs for some people!aidan– aidan2020年09月04日 01:47:25 +00:00Commented Sep 4, 2020 at 1:47
If you've done a bunch of coding already with parseInt and don't want to add ",10" to everything, you can just override the function to make base 10 the default:
window._oldParseInt = window.parseInt;
window.parseInt = function(str, rad) {
if (! rad) {
return _oldParseInt(str, 10);
}
return _oldParseInt(str, rad);
};
That may confuse a later reader, so making a parseInt10() function might be more self-explanatory. Personally I prefer using a simple function than having to add ",10" all the time - just creates more opportunity for mistakes.
10
(decimal) unless the number to parse is prefixed with0x
, e.g.0xFF
, in which case the base parameter defaults to 16. Hopefully, one day, this issue will be a distant memory.+'08' === 8
? True! Maybe you really needparseInt
for your real code, but not for the above.Number('08')
0
orundefined
and the string's number begins with a0
digit not followed by anx
orX
, then the implementation may, at its discretion, interpret the number either as being octal or as being decimal. Implementations are encouraged to interpret numbers in this case as being decimal." (my emphasis)