为什么JavaScript在数字前面加0时会将其视为八进制数

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

JS 引擎将数字x转换为八进制数。为什么会这样?我该如何防止它发生?


2
@Andy - 是10,不是8。他在问为什么在数字前加0会让它被认为是八进制。我理解他的疑惑。 - Reinstate Monica Cellio
以0开头的数字字面值总是被解释为八进制值。 - Robert Kock
这是一种非标准做法,在严格模式下被禁止。请参阅 Leading zero in javascript - Oriol
1
如果我们在数字前加上0x,则它将把数字转换为十六进制。 - Jagajit Prusty
1
这个回答解决了你的问题吗?JavaScript中带前导零的数字 - FZs
显示剩余2条评论
3个回答

21

我认为我的回答在这里已经回答了这个问题,但是这个问题并不完全是重复的,所以我会附上我的回答副本。

历史

问题在于十进制整数字面量不能有前导零:

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits(opt)

然而,ECMAScript 3允许(作为可选扩展)解析带有前导零的字面量,其基数为8:
OctalIntegerLiteral ::
    0 OctalDigit
    OctalIntegerLiteral OctalDigit

但是ECMAScript 5在严格模式下禁止这样做:

一个符合规范的实现,当处理严格模式代码(见10.1.1)时,不能扩展NumericLiteral的语法,以包括OctalIntegerLiteral,如B.1.1所述。

ECMAScript 6引入了BinaryIntegerLiteralOctalIntegerLiteral,因此我们现在有更加连贯的文字:

  • BinaryIntegerLiteral,以0b0B为前缀。
  • OctalIntegerLiteral,以0o0O为前缀。
  • HexIntegerLiteral,以0x0X为前缀。

旧的OctalIntegerLiteral扩展已更名为LegacyOctalIntegerLiteral,在非严格模式下仍然允许使用。

结论

因此,如果要解析8进制数字,请使用0o0O前缀(旧浏览器不支持),或使用parseInt

如果要确保您的数字将以10进制解析,请删除前导零,或使用parseInt

示例

  • 010
    • 在严格模式下(需要 ECMAScript 5),它会抛出错误。
    • 在非严格模式下,它可能会抛出错误或返回 8(实现相关)。
  • 0o10, 0O10
    • 在 ECMAScript 6 之前,它们会抛出错误。
    • 在 ECMAScript 6 中,它们会返回 8
  • parseInt('010', 8)
    • 它会返回 8
  • parseInt('010', 10)
    • 它会返回 10

2

如果数字具有有效的八进制形式,JS将前导零的数字视为八进制,否则它将其视为十进制。为了避免这种情况,请不要在源代码中使用前导零。

"Original Answer"的翻译是"最初的回答"。

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

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

或者使用“严格模式”以不允许使用前导零。最初的回答中包含了这句话。

'use strict'

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


"未捕获的语法错误:在严格模式下不允许带有前导零的小数。" - astroanu

2
这是因为一些JavaScript引擎将前导零解释为八进制数字字面量。这在ECMAScript规范的附录中有定义。
然而,在严格模式下,符合规范的实现不能实现这一点-请再次参阅ECMAScript规范
“当处理严格模式代码(参见10.1.1)时,符合规范的实现不得扩展NumericLiteral的语法,以包括B.1.1中描述的OctalIntegerLiteral。”
由于存在这种歧义,最好不要使用前导零。

1
这不是JS字面量的语法,而是一种被强烈反对的非标准扩展,在严格模式下明确禁止使用。 - Oriol
没错 :) 没注意到这个问题。让我给了+1。回答已经修正。 - Ondra Žižka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接