ChatGPT解决这个技术问题 Extra ChatGPT

How do I work around JavaScript's parseInt octal behavior?

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.

Step 1) Do yourself a favor and always include the radix as mentioned in the previous answers as well as in Doug's book. Step 2) If you are serious about learning JavaScript, then get yourself a copy of Doug's book. It is invaluable. My fav book so far. Here's a review fyi: realtech.burningbird.net/learning-javascript/basics/…
In ECMAScript 5th Edition-compatible browsers, such as Internet Explorer 9, the base parameter defaults to 10 (decimal) unless the number to parse is prefixed with 0x, e.g. 0xFF, in which case the base parameter defaults to 16. Hopefully, one day, this issue will be a distant memory.
How about just +'08' === 8? True! Maybe you really need parseInt for your real code, but not for the above.
a) this is not a bug, fix the title b) Number('08')
@portman: "the 5th Edition...introduces a breaking change that eliminates this behavior" Probably worth pointing out that even in the 3rd edition (13 years ago), implementations were "encouraged" not to do it: "When radix is 0 or undefined and the string's number begins with a 0 digit not followed by an x or X, 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)

g
groovecoder

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

Number 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).
Number(08); gives me 8 in Firefox and IE.
it'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"
Still, 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.
Old question, but note that Number is different than parseInt: stackoverflow.com/a/4090577
K
Karl Guertin

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...


Why two operations when one binary or would suffice?
@Oleg, Why would one suffice?
@Grodriguez, and when 0 in |0 is a string?
This whole question is about alternatives to parseInt for converting strings to integers. Thus: always.
P
Portman

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.


if 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.
Riiiiiiight, 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.
@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.)
Actually it's really important to wrap parseInt for convenient use in functional expressions, like map 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 by parseInt as the base unless you wrap it.
J
Jason S
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.


R
RichieHindle

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?
Why the devil is it not defaulted to base 10
Maybe 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.
it is defaulted to base 10 but leading zeros are a widespread way to indicate octal.
A
Andrew Duffy

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)}

yes, that would be naughty -- it would break other code that relied on the standard behavior.
That is true, but there isn't much of that. It also isn't standard behaviour - octal support is optional.
But 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 works parseInt("0xFFFFFF") === 0
S
SoEzPz

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

MDN Link

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.


M
Mark Hall

How about this for decimal:

('09'-0) === 9  // true

('009'-0) === 9 // true

i
ingredient_15939

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.


A
Andrija

This issue cannot be replicated in latest Chrome nor Firefox (2019).


Yeah, 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. :)
That's going to cause some really nasty bugs for some people!