parseInt(null,24)=== 23…等等,什么?


226

好了,所以我在弄乱parseInt看看它如何处理尚未初始化的值,我偶然发现了这个gem。对于基数为24或更高的基数,将发生以下情况。

parseInt(null, 24) === 23 // evaluates to true

我在IE,Chrome和Firefox中对其进行了测试,它们都警告为true,因此我认为它必须在某个地方的规范中。快速的Google搜索没有给我任何结果,所以我在这里,希望有人可以解释。

我记得我听过克罗克福德的讲话,是typeof null === "object"因为疏忽导致对象和空值在内存或类似内容中具有几乎相同的类型标识符,但我现在找不到该视频。

试试看:http : //jsfiddle.net/robert/txjwP/

编辑校正:较高的基数返回不同的结果,32返回785077
编辑2来自zzzzBov:[24...30]:23, 31:714695, 32:785077, 33:859935, 34:939407, 35:1023631, 36:1112745


tl; dr

解释为什么parseInt(null, 24) === 23是真实的陈述。


49
多么古怪。JavaScript始终使您保持警惕。
FishBasketGordo 2011年

1
数据点:alert(parseInt(null, 34) === 23)产生false
斯蒂芬P

1
alert(parseInt(null,26)===23);也产生真实的?!?!
Petar Ivanov

6
[24...30]:2331:71469532:78507733:85993534:93940735:102363136:1112745[37...]:NaN
zzzzBov

1
另外请注意,undefined由于第一个参数返回30的奇数结果
zzzzBov 2011年

Answers:


240

它正在转换null为字符串"null"并尝试将其转换。对于基数0到23,没有可以转换的数字,因此返回NaN。在24,"n"第14个字母被添加到数字系统。在31,"u"添加第21个字母,并且可以解码整个字符串。在37处,不再可以生成任何有效数字集,并且返回NaN。

js> parseInt(null, 36)
1112745

>>> reduce(lambda x, y: x * 36 + y, [(string.digits + string.lowercase).index(x) for x in 'null'])
1112745

3
@Tomalak:谁说它正在使用toString()
伊格纳西奥·巴斯克斯

3
@Ignacio。其实我错了。我没有意识到37是指基数。对于那个很抱歉。
Mike Samuel

3
@Robert,不,我很困惑,以为他要求的不是他要求的。这是正确的答案。到处都道歉。
Mike Samuel

19
我仍然认为该答案可能与某些参考有关。尽管它是完全正确的,但实际上只是一个很大的主张……
Lightness Races in Orbit

4
@Tomalak-检查我所有答案的答案。这个答案是正确的(也是第一个),所以我认为它应该仍然是公认的答案。尽管从根本上解释引擎盖下发生的事情是无害的;)
David Titarenco

118

Mozilla 告诉我们

函数parseInt 将其第一个参数转换为字符串,对其进行解析,然后返回整数或NaN。如果不是NaN,则返回的值将是第一个参数的十进制整数表示形式,它作为指定基数(基数)中的数字。例如,基数10表示要从十进制数,八进制八进制,十六进制十六进制等进行转换。对于半径大于10的字母,字母表示大于9的数字。例如,对于十六进制数字(以16为底),使用A至F。

规范,15.1.2.2/1告诉我们,转换为字符串使用进行内置ToString,其中(按9.8)收益率"null"(不要与混淆toString,这会产生"[object Window]"!)。

因此,让我们考虑一下parseInt("null", 24)

当然,这并不是完整的以24为底的数字字符串,但是“ n”是:十进制23

现在,停止解析十进制23被拉出后,因为"u" 没有在基本-24系统中发现:

如果S包含任何不是基数R的字符,则令Z为S的子字符串,该子字符串由第一个这样的字符之前的所有字符组成;否则,让Z为S。[15.1.2.2/11]

(这就是为什么parseInt(null, 23)(和较低的半径)给您NaN而不是23:"n"不在base-23系统中的原因。)


2
这是parseInt的非常悲惨的行为(我在想为什么在这种情况下,尽管没有例外,但它还是没有设计)。如果可以的话,我宁愿使用NUMBER()代替。
Grijesh Chauhan 2014年

79

伊格纳西奥·巴斯克斯·阿布拉姆斯(Ignacio Vazquez-Abrams)是正确的,但让我们确切地了解它如何工作的 ...

来自15.1.2.2 parseInt (string , radix)

调用parseInt函数时,将执行以下步骤:

  • 令inputString为ToString(string)。
  • 令S为新创建的inputString子字符串,它由不是StrWhiteSpaceChar的第一个字符以及该字符之后的所有字符组成。(换句话说,删除前导空白。)
  • 让符号为1。
  • 如果S不为空并且S的第一个字符是减号-,则使符号为-1。
  • 如果S不为空并且S的第一个字符是加号+或减号-,则从S中删除第一个字符。
  • 设R = ToInt32(基数)。
  • 令stripPrefix为true。
  • 如果R≠0,则a。如果R <2或R> 36,则返回NaN。b。如果R≠16,则让stripPrefix为false。
  • 否则,R = 0 a。令R = 10。
  • 如果stripPrefix为true,则一个。如果S的长度至少为2,并且S的前两个字符为“ 0x”或“ 0X”,则从S中删除前两个字符,并使R = 16。
  • 如果S包含任何不是基数R的字符,则令Z为S的子字符串,该子字符串由第一个这样的字符之前的所有字符组成;否则,让Z为S。
  • 如果Z为空,则返回NaN。
  • 令mathInt为Z以基数R表示的数学整数值,使用字母AZ和az表示从10到35的数字。(但是,如果R为10并且Z包含20个以上有效数字,则每个有效数字根据实现的选择,第20个位之后的数字可以用0代替;并且如果R不是2、4、8、10、16或32,则mathInt可能是与实现相关的数学整数的近似值Z以基数R表示的值。)
  • 令number为mathInt的Number值。
  • 返回符号×数字。

注意parseInt只能将字符串的开头部分解释为整数值;它会忽略无法解释为整数符号一部分的任何字符,并且不会给出任何此类字符被忽略的指示。

这里有两个重要部分。我把它们都加粗了。因此,首先,我们必须找出的toString表示null形式。我们需要Table 13 — ToString Conversions在9.8.0节中查看该信息:

在此处输入图片说明

太好了,所以现在我们知道在toString(null)内部进行操作会产生一个'null'字符串。很好,但是如何处理提供的基数中无效的数字(字符)?

我们在上面看,15.1.2.2然后看到以下注释:

如果S包含任何不是基数R的字符,则令Z为S的子字符串,该子字符串由第一个这样的字符之前的所有字符组成;否则,让Z为S。

这意味着我们将处理指定基数之前的所有数字,而忽略其他所有内容。

基本上,parseInt(null, 23)操作与相同parseInt('null', 23)。将u导致两个l的被忽略(即使它们的基数23的一部分)。因此,我们只能解析n,使整个语句成为的同义词parseInt('n', 23)。:)

无论哪种方式,很好的问题!


33
parseInt( null, 24 ) === 23

相当于

parseInt( String(null), 24 ) === 23

相当于

parseInt( "null", 24 ) === 23

以24为底的数字是0、1、2、3、4、5、6、7、8、9,a,b,c,d,e,f,...,n。

语言规范说

  1. 如果S包含任何不是基数R的字符,则令Z为S的子字符串,该子字符串由第一个这样的字符之前的所有字符组成;否则,让Z为S。

这是确保C样式整数文字15L正确解析的部分,因此上述内容等同于

parseInt( "n", 24 ) === 23

"n" 是上面数字列表的第23个字母。

优质教育


16

我想null会转换成字符串"null"。所以n实际上是23在“ base24”中(在“ base25” +中相同),u在“ base24”中无效,因此字符串的其余部分null将被忽略。这就是为什么它输出23直到u在'base31'中变为有效。


7

parseInt使用字母数字表示,然后在以24为基数的“ n”中有效,但是“ u”是无效字符,则parseInt仅解析值“ n”...。

parseInt("n",24) -> 23

作为示例,请尝试以下操作:

alert(parseInt("3x", 24))

结果将为“ 3”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.