9

In reviewing parseInt(string, radix) in: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt

all 13 examples make perfect sense except for this one.

According to one example, parseInt(015, 10) will return 13. This makes sense assuming that numericals that begin with 0 are treated as an octal, regardless of the 10 that appears in the radix position.

So if the octal is specified as it is in the question header: parseInt(021, 8)

Then why wouldn't this be 17 (vs. 15 per the Mozilla documentation and in my tests in jsfiddle?

Any insight would be appreciated.

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
James Lee
  • 754
  • 8
  • 13
  • 1
    If you read the first line of the MDN docs that you linked you can see that the first argument should be a string. – Daniel Tate May 01 '19 at 04:38
  • 9
    When you write a number (not a string) as `021` that is in octal notation. So when the engine parses your code, it parses that to be the number 17 (decimal). When you call parseInt, 17 is converted to the string "17" and then decoded as an octal number. 17 octal = 15 decimal. Change it to a string `"021"` and you get your expected result. – some May 01 '19 at 04:53
  • `parseInt(021,10) === parseInt(021) === 17`. The root of the issue was passing the "8" as the radix. – RichS May 01 '19 at 04:54
  • `parseInt(021, 8) === parseInt(017, 10) === 15`. (Because of the internal treatment of 021) – RichS May 01 '19 at 04:57
  • Javascript allows you to write the same number in decimal `31`, hex `0x1F`, binary `0b11111` or octal `037`. There is also a new type: BigInt, `31n`. – some May 01 '19 at 04:59
  • Thank you @some, your answer was very clear! – James Lee May 01 '19 at 05:00
  • 1
    @RichS No, the root of the issue was not passing `8` as the radix. If anything it was passing `021` as a number instead of a string. This is the point of the example. – some May 01 '19 at 05:07
  • parseInt(021) would have been 17 if he left the 8 out, even if the 021 were a number. – RichS May 01 '19 at 05:11

3 Answers3

20

This is because 0n is octal notation in javascript, just like Oxn is hex notation:

console.log(021 === 0x11 && 021 === 17);

So what you wrote got evaluated as parseInt(17, 8);

Then this 17 number gets coerced to the string "17" and the result is 15.

console.log(parseInt(17, 8))

Note that all this would not have happened in strict mode, where 0n notation has been deprecated:

(function(){
  "use strict";
  // Syntax Error
  console.log(parseInt(015, 8))
})();
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • This is the direct answer to the question asked. The input to parseInt *can* be a number, although it's *convention* (and highly recommend) to normally pass in a string. – RichS May 01 '19 at 04:52
  • 1
    Very good that you mentioned **strict mode**. – some May 01 '19 at 05:09
  • 4
    Why would you say that `015` is invalid as octal? – Tommy Andersen May 01 '19 at 08:56
  • 015? Did you mean 018 or 019 etc? – Salman A May 01 '19 at 09:45
  • 2
    Yes you guys are right dunno what I had in mind... – Kaiido May 01 '19 at 10:19
  • 1
    @RichS nobody on this answer had any doubt about what this function accepts (any type) and what it does to it (call toString). Maybe you want to comment on Gerardo's answer instead. Ps: It's not parseInt that doesn't accept octal notation... – Kaiido May 02 '19 at 22:38
  • It's also useful to note that `021` is treated as octal but `"021"` (_quoted_ form) as a decimal. So, `parseInt("021")` will output 21. – Saeed Ahadian Dec 08 '19 at 19:23
12

The first argument of parseInt should be a string. The same MDN link says:

The value to parse. If the string argument is not a string, then it is converted to a string (using the ToString abstract operation).

You can see that this works as expected:

console.log(parseInt("021", 8))

The problem in your tests is that you're using a number, not a string. When you use 021 as a number, as you already knows (when you said "numericals that begin with 0 are treated as an octal"), it gets converted to "17":

console.log(021.toString())

And that gives you the result you're seeing:

console.log(parseInt("17", 8))
Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
  • This is correct as per the first line of the MDN documentation. – Daniel Tate May 01 '19 at 04:37
  • I may be stating the obvious, but 021 is the *octet* representation. So, 021 = 0*8^2 + 2*8^1 + 1*8^0 = 0 + 16 + 1 = 17. It gets treated like an *octet* string because of the 0 padding. If you leave off the "0", then parseInt(21) returns 21, whereas parseInt(021) returns 17, *even if the input is already a number and **not** a string. – RichS May 01 '19 at 04:45
4

When you type 021 then this is valid octal number and because prefix 0 JS convert it to decimal 17. But if you type not valid octal number e.g. 019 then JS will NOT convert it but treat as decimal

console.log(021)    // octal
console.log(019)    // not octal

if( 021 < 019 ) console.log('Paradox');
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • Technically is correct, since `9` is not part of the octal system the runtime considers it as decimal – fjcero Mar 21 '20 at 21:27