26
var x = 010;
console.log(x); //8

JS engine convert the number x to octal number. Why it happens? How can I prevent it?

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
Jagajit Prusty
  • 2,070
  • 2
  • 21
  • 39
  • 2
    @Andy - 10, not 8. He's asking why prefixing a number with a 0 makes it assume it's octal. I don't blame him for asking. – Reinstate Monica Cellio May 03 '16 at 12:12
  • A literal numeric value that starts with a 0 is always interpreted as an octal value. – Robert Kock May 03 '16 at 12:13
  • Hah, yeah, I didn't ask that question properly. I know why it logs it as octal, I just wondered if 10 was the expected output from the OP. – Andy May 03 '16 at 12:14
  • This is a non-standard practice forbidden in strict mode. See [Leading zero in javascript](http://stackoverflow.com/a/28354557/1529630) – Oriol May 03 '16 at 12:17
  • 1
    If we prefix a number with 0x then it will convert the number to Hexadecimal as well – Jagajit Prusty May 04 '16 at 04:53
  • On not strict mode, it will convert to octal if it CAN, `010 === 08` that will log true. Now you know why. – ibrahim tanyalcin May 02 '19 at 12:17
  • 1
    Does this answer your question? [Number with leading zero in JavaScript](https://stackoverflow.com/questions/6505033/number-with-leading-zero-in-javascript) – FZs May 31 '22 at 17:28

3 Answers3

21

I think my answer here answers the question, but the question is not exactly a duplicate, so I include a copy of my answer.

History

The problem is that decimal integer literals can't have leading zeros:

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits(opt)

However, ECMAScript 3 allowed (as an optional extension) to parse literals with leading zeros in base 8:

OctalIntegerLiteral ::
    0 OctalDigit
    OctalIntegerLiteral OctalDigit

But ECMAScript 5 forbade doing that in strict-mode:

A conforming implementation, when processing strict mode code (see 10.1.1), must not extend the syntax of NumericLiteral to include OctalIntegerLiteral as described in B.1.1.

ECMAScript 6 introduces BinaryIntegerLiteral and OctalIntegerLiteral, so now we have more coherent literals:

  • BinaryIntegerLiteral, prefixed with 0b or 0B.
  • OctalIntegerLiteral, prefixed with 0o or 0O.
  • HexIntegerLiteral, prefixed with 0x or 0X.

The old OctalIntegerLiteral extension has been renamed to LegacyOctalIntegerLiteral, which is still allowed in non-strict mode.

Conclusion

Therefore, if you want to parse a number in base 8, use the 0o or 0O prefixes (not supported by old browsers), or use parseInt.

And if you want to be sure your numbers will be parsed in base 10, remove leading zeros, or use parseInt.

Examples

  • 010
    • In strict mode (requires ECMAScript 5), it throws.
    • In non strict mode, it may throw or return 8 (implementation dependent).
  • 0o10, 0O10
    • Before ECMAScript 6, they throw.
    • In ECMAScript 6, they return 8.
  • parseInt('010', 8)
    • It returns 8.
  • parseInt('010', 10)
    • It returns 10.
Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
2

It's because some JavaScript engines interpret leading zeros as octal number literals. It is defined in an appendix of ECMAScript specification.

However, in strict mode, the conforming implementations must not implement that - see ECMAScript specification again:

A conforming implementation, when processing strict mode code (see 10.1.1), must not extend the syntax of NumericLiteral to include OctalIntegerLiteral as described in B.1.1.

Because of this ambiguity, it's better not to use leading zeros.

Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
2

JS treat numbers with leading zeros as octal only if they valid octal, if not then it treat it as decimal. To prevent this not use leading zeros in your source code

console.log(010, 10, +"010")

if (021 < 019) console.log('Paradox');

or use strict mode to not allow using leading zeros

'use strict'

if (021 < 019) console.log('Paradox');
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345