JavaScript中的parseInt()函数和前导零

133

Javascript的parseInt函数似乎不能完全正常工作。

parseInt("01") returns 1
parseInt("02") returns 2
parseInt("03") returns 3
parseInt("04") returns 4
parseInt("05") returns 5
parseInt("06") returns 6
parseInt("07") returns 7
parseInt("08") returns 0
parseInt("09") returns 0

这个无法解释。试一下吧。 (jsFiddle)

编辑自从这个问题被提出和回答之后,将默认使用八进制基数的“特性”已被弃用。[1] [2]


9
你不能解释那个。是的,你可以=> https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt - gen_Eric
3
自古以来,以0开头的数字代表八进制,而0x则代表十六进制。我相信这在所有语言中都是通用的,但我可能错了。 - Selvakumar Arumugam
3
FYI: jsFiddle 是比 http://www.w3schools.com/jsref/tryit.asp 更好的在线 JavaScript 测试工具。 - gen_Eric
2
@JohnHartsock 是的,这是因为我们都在这篇帖子上http://stackoverflow.com/questions/8761997/difference-between-datetimes/8763241#8763241 - savinger
3
截至2015年,在Windows的现代标准浏览器中已经没有默认八进制的行为了。我只能在Safari 5上重现这种情况。 - d.raev
显示剩余3条评论
7个回答

192

这是因为如果一个数字以'0'开头,它会被视为八进制。

您可以通过将基数作为第二个参数传递来强制指定基数。

parseInt("09", 10) // 9
根据文档,第二个参数是可选的,但是像你的例子一样,它并不总是被默认为10。

1
是的,但如果假定为八进制,则 09 应该返回 11 而不是 0。 - Peeyush Kushwaha
2
@PeeyushKushwaha:反过来说,八进制中的11是十进制中的909不是一个有效的八进制数。 - gen_Eric
但是我想在parseInt之后得到09,有什么解决方法吗? - Pardeep Jain

44

调用 parseInt 函数时,应该始终在第二个参数中指定一个进制:

parseInt("08", 10);
早期版本的JavaScript将以0开头的字符串视为八进制(当未指定基数时),而0809都不是有效的八进制数字。
从Mozilla文档中可知:
如果radix未定义或为0,则JavaScript会假定以下情况:
- 如果输入字符串以 "0x" 或 "0X" 开头,基数为16(十六进制)。 - 如果输入字符串以 "0" 开头,基数为8(八进制)。这个特性是非标准的,一些实现故意不支持它(而是使用基数10)。因此,在使用parseInt时始终要指定一个基数。 - 如果输入字符串以其他任何值开头,则基数为10(十进制)。
如果第一个字符无法转换为数字,则parseInt返回NaN。
ECMAScript 3标准中也可以看到:
当radix为0或未定义时,字符串的数字以0开始但不跟随xX,则实现可以自行解释该数字,即将其解释为八进制或十进制。 在这种情况下,鼓励实现将数字解释为十进制。
最新版本的JavaScript(ECMAScript 5放弃了这种行为,但仍然应指定基数以满足较旧的浏览器。

由于这已经被弃用,将来使用前导零没问题,对吧? - Pacerier

16

有一个基数参数

parseInt(value, base)

其中base是进制。

在这种情况下,您正在评估十进制数,因此使用

parseInt(value, 10);

4

在新版浏览器中,这似乎并不完全有效。如果您执行 'parseInt("08")',Internet Explorer 9和10将返回8,而Internet Explorer 8和之前的版本将返回0(IE10在怪异模式下也将返回0)。

最新版的Chrome也返回8,因此他们可能最近改变了解释方式。


是的,这种行为已经改变了。我会更新我的答案。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation - Wayne
1
是的,Firefox和Chrome的最新版本现在没有问题。 - mythicalcoder

3

这个问题现在已经被废弃了。但是您仍然可以使用 parseInt 中的基数来将其他进制的数字转换为十进制。例如,

var baseTwoNumber = parseInt('0010001', 2);

返回 17(即 0010001 的十进制表示)。


0

提示:正如您现在所知道的,当默认转换为八进制时已被弃用。以下是您在旧版浏览器中修复它的方法

// ES-5 15.1.2.2
if (parseInt('08') !== 8 || parseInt('0x16') !== 22) {
    parseInt = (function (origParseInt) {
        var hexRegex = /^0[xX]/;
        return function parseIntES5(str, radix) {
            str = String(str).trim();
            if (!Number(radix)) {
                radix = hexRegex.test(str) ? 16 : 10;
            }
            return origParseInt(str, radix);
        };
    }(parseInt));
}

如果您在编程中使用仅带前导零的常数(而不是字符串),则在当前所有浏览器中仍将其视为八进制。 - Agamemnus

0
问题现在在大多数浏览器中似乎已经改变了。
Firefox 51.0.1(64位)
parseInt("09")   // 9

Chrome 55.0.2883.95(64位)

parseInt("09")   // 9

Safari 10.0 (12602.1.50.0.10)

parseInt("09")   // 9

=====

推荐做法

话虽如此,为了更加安全并避免问题,建议按照被接受的答案中提到的使用基数参数。

parseInt("09", 10)    // 9

额外测试

我只是想测试一下,如果参数不是字符串。Chrome和Safari给出了精确的结果。Firefox也返回正确的结果,但带有警告。

parseInt(09)     // 9. (Warning: SyntaxError: 09 is not a legal ECMA-262 octal constant)

如果数值以0开头且为数字,parseInt仍然会使用8进制。尝试parseInt(020)。 - sirrocco
是的。我甚至指出了建议的答案。并且我知道要避免的最佳实践和不良特性。因此,我在我的答案中也给出了推荐做法 - mythicalcoder

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