为啥 parseInt(8,3) == NaN 和 parseInt(16,3) == 1?
Posted
技术标签:
【中文标题】为啥 parseInt(8,3) == NaN 和 parseInt(16,3) == 1?【英文标题】:Why is it that parseInt(8,3) == NaN and parseInt(16,3) == 1?为什么 parseInt(8,3) == NaN 和 parseInt(16,3) == 1? 【发布时间】:2017-01-01 23:50:59 【问题描述】:我正在阅读 this,但我对 parseInt 中使用基数参数一章中所写的内容感到困惑
为什么parseInt(8, 3)
→NaN
和parseInt(16, 3)
→1
?
AFAIK 8 和 16 不是基数为 3 的数字,所以 parseInt(16, 3)
也应该返回 NaN
【问题讨论】:
另一个可以通过静态类型解决的问题(或者至少不会将整数隐式转换为字符串):P @Navin 这与静态类型与动态类型无关(正如您自己所指出的那样)。这里的问题是弱类型而不是强类型。 当我看到这个问题的标题时,我心想,“可能是因为loljavascript”。看到答案,我判断我的直觉基本上是正确的。 【参考方案1】:这是人们一直都会遇到的事情,即使他们知道这一点。 :-) 你看到这个的原因与parseInt("1abc")
返回 1 的原因相同:parseInt
在第一个无效字符处停止并返回它在该点的任何内容。如果没有要解析的有效字符,则返回NaN
。
parseInt(8, 3)
表示“以 3 为基数解析 "8"
”(注意它将数字 8
转换为字符串;details in the spec)。但在基数 3 中,个位数只是 0
、1
和 2
。这就像要求它以八进制解析"9"
。因为没有没有个有效字符,所以你得到了NaN
。
parseInt(16, 3)
要求它解析基数为 3 的 "16"
。由于它可以解析 1
,它可以解析,然后它在 6
处停止,因为它无法解析它。所以它返回1
。
由于这个问题引起了很多关注,并且可能在搜索结果中排名很高,因此这里列出了在 JavaScript 中将字符串转换为数字的选项,以及它们的各种特性和应用程序(摘自我在 SO 上的另一个答案) :
parseInt(str[, radix])
- 将字符串的开头尽可能多地转换为整数(整数),忽略末尾的额外字符。所以parseInt("10x")
是10
; x
被忽略。支持可选的基数(数字基数)参数,因此parseInt("15", 16)
是21
(15
十六进制)。如果没有基数,则假定为十进制,除非字符串以 0x
(或 0X
)开头,在这种情况下,它会跳过这些并假定为十六进制。 (一些浏览器过去会将以0
开头的字符串视为八进制;这种行为从未被指定,并且在 ES5 规范中是 specifically disallowed。) 如果找不到可解析的数字,则返回 NaN
。
parseFloat(str)
- 与parseInt
类似,但处理浮点数且仅支持十进制。字符串上的额外字符再次被忽略,所以parseFloat("10.5x")
是10.5
(x
被忽略)。由于只支持十进制,parseFloat("0x15")
是0
(因为解析在x
结束)。如果找不到可解析的数字,则返回 NaN
。
一元+
,例如+str
- (例如,隐式转换) 使用浮点和 JavaScript 的标准数字表示法将 整个 字符串转换为数字(只有数字和小数点 = 小数;@ 987654362@ prefix = hex; 0o
prefix = octal [ES2015+]; some 实现将其扩展为将前导 0
视为八进制,但不是在严格模式下)。 +"10x"
是 NaN
因为 x
被不忽略。 +"10"
是 10
,+"10.5"
是 10.5
,+"0x15"
是 21
,+"0o10"
是 8
[ES2015+]。有一个问题:+""
是 0
,而不是您所期望的 NaN
。
Number(str)
- 完全像隐式转换(例如,像上面的一元 +
),但在某些实现上较慢。 (这可能并不重要。)
【讨论】:
所以parseInt
首先在第一个参数上使用toString
?这是有道理的。
@evolutionxbox:是的,这是parseInt
算法的第一步:ecma-international.org/ecma-262/7.0/…
我想123e-2
给1
因为它先变成1.23
,然后解析在小数点处停止?
“这是人们一直在纠结的事情,即使他们知道这一点” -> 只有我认为这应该是一个错误吗?例如,在 Java 中做同样的事情,每次都会给你一个NumberFormatException
。
@SvenMarnach:parseInt
的 那 部分(将第一个参数强制为字符串)是有道理的。 parseInt
的目的是将字符串解析为整数。所以如果你给它一些不是字符串的东西,那么让它的字符串表示开始是有意义的。 在之后它做了什么,那是一个完整的“另一个故事......【参考方案2】:
出于同样的原因
>> parseInt('1foobar',3)
<- 1
在the doc 中,parseInt
接受一个字符串。和
如果string不是字符串,则转换为字符串
所以16
、8
或'1foobar'
首先转换为字符串。
然后
如果
parseInt
遇到的字符不是指定基数中的数字,则忽略它和所有后续字符
意味着它可以转换到它可以转换的地方。 6
、8
和 foobar
将被忽略,仅转换之前的内容。如果没有,则返回NaN
。
【讨论】:
【参考方案3】:/***** 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
【讨论】:
以上是关于为啥 parseInt(8,3) == NaN 和 parseInt(16,3) == 1?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 parseInt(key) === NaN 总是评估为 false
为啥我在使用 parseINt 或 undefined 时得到 NaN?