为什么 parseInt(8,3) == NaN 和 parseInt(16,3) == 1?

Why is it that parseInt(8,3) == NaN and parseInt(16,3) == 1?

我正在阅读 this 但我对 parseInt 中带有基数参数 章节

的内容感到困惑

为什么parseInt(8, 3)NaNparseInt(16, 3)1

AFAIK 8 和 16 不是基数 3,所以 parseInt(16, 3) 也应该 return NaN

这是人们经常犯的错误,即使他们知道了。 :-) 您看到这个的原因与 parseInt("1abc") returns 1 相同:parseInt 在第一个无效字符处停止,returns 在该点处的任何内容。如果没有可解析的有效字符,则 returns NaN.

parseInt(8, 3)表示"parse "8" in base 3"(注意它将数字8转换为字符串;details in the spec)。但是在基数 3 中,个位数只是 012。这就像要求它以八进制解析 "9" 一样。由于 没有 个有效字符,您得到 NaN.

parseInt(16, 3) 要求它在基数 3 中解析 "16"。因为它可以解析 1,所以它会解析,然后在 6 处停止,因为它无法解析它。所以它 returns 1.


由于这个问题受到了很多关注并且可能在搜索结果中排名靠前,这里列出了 JavaScript 中将字符串转换为数字的选项,以及它们的各种特性和应用(摘自另一个答案我在这里的 SO):

  • parseInt(str[, radix]) - 将字符串的开头尽可能多地转换为一个完整(整数)数字,忽略末尾的额外字符。所以 parseInt("10x")10x 被忽略。支持可选的基数(数字基数)参数,因此 parseInt("15", 16)21(十六进制的 15)。如果没有基数,则假定为十进制,除非字符串以 0x(或 0X)开头,在这种情况下它会跳过这些并假定为十六进制。 (一些浏览器曾经将以 0 开头的字符串视为八进制;这种行为从未被指定,在 ES5 规范中是 specifically disallowed。) Returns NaN 如果找不到可解析的数字。

  • parseFloat(str) - 与 parseInt 相似,但支持浮点数且仅支持小数。字符串上的额外字符再次被忽略,因此 parseFloat("10.5x")10.5x 被忽略)。由于仅支持十进制,因此 parseFloat("0x15")0(因为解析在 x 处结束)。 Returns NaN 如果找不到可解析的数字。

  • 一元 +,例如+str - (例如,隐式转换) 使用浮点数和 JavaScript 将 整个 字符串转换为数字标准数字表示法(仅数字和小数点 = 十进制;0x 前缀 = 十六进制;0o 前缀 = 八进制 [ES2015+];一些 实现扩展它以处理前导 0 作为八进制,但不是在严格模式下)。 +"10x"NaN 因为 x 而不是 被忽略。 +"10"10+"10.5"10.5+"0x15"21+"0o10"8 [ES2015+] .有一个陷阱:+""0,而不是您可能期望的 NaN

  • Number(str) - 完全像隐式转换(例如,像上面的一元 +),但在某些实现上更慢。 (并不是说这很重要。)

出于同样的原因

>> parseInt('1foobar',3)
<- 1

the doc中,parseInt接受一个字符串。并且

If string is not a string, then it is converted to a string

因此168'1foobar'首先转换为字符串。

然后

If parseInt encounters a character that is not a numeral in the specified radix, it ignores it and all succeeding characters

意味着它会尽可能地转换。 68foobar被忽略,只转换之前的内容。如果什么都没有,则返回NaN

/***** Radix 3: Allowed numbers are [0,1,2] ********/
parseInt(4, 3); // NaN - We can't represent 4 using radix 3 [allowed - 0,1,2]

parseInt(3, 3); // NaN - We can't represent 3 using radix 3 [allowed - 0,1,2]

parseInt(2, 3); // 2   - yes we can !

parseInt(8, 3); // NaN - We can't represent 8 using radix 3 [allowed - 0,1,2]

parseInt(16, 3); // 1  
//'16' => '1' (6 ignored because it not in [0,1,2])    

/***** Radix 16: Allowed numbers/characters are [0-9,A-F] *****/ 
parseInt('FOX9', 16); // 15  
//'FOX9' => 'F' => 15 (decimal value of 'F')
// all characters from 'O' to end will be ignored once it encounters the out of range'O'
// 'O' it is NOT in [0-9,A-F]

更多示例:

parseInt('45', 13); // 57
// both 4 and 5 are allowed in Radix is 13 [0-9,A-C]

parseInt('1011', 2); // 11 (decimal NOT binary)

parseInt(7,8); // 7
// '7' => 7 in radix 8 [0 - 7]

parseInt(786,8); // 7 
// '78' => '7' => 7 (8 & next any numbers are ignored bcos 8 is NOT in [0-7])

parseInt(76,8); // 62 
// Both 7 & 6 are allowed '76' base 8 decimal conversion is 62 base 10