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

Rob*_*ert 226 javascript parseint

好吧,所以我正在搞乱parseInt来看看它如何处理尚未初始化的值,我偶然发现了这个宝石.对于任何24或以上的基数,都会发生以下情况.

parseInt(null, 24) === 23 // evaluates to true
Run Code Online (Sandbox Code Playgroud)

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

我记得听过他说的Crockford演讲,typeof null === "object"因为疏忽导致Object和Null在内存中有一个几乎相同的类型标识符,或者沿着这些行,但我现在找不到那个视频了.

试一试: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;博士

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

Ign*_*ams 239

它正在转换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
Run Code Online (Sandbox Code Playgroud)

  • 我仍然认为这个答案可以用一些参考文献.虽然它完全正确,但它只是一个大的断言...... (19认同)
  • @Tomalak - 检查所有参考文献的答案.这个答案是正确的(和第一个),所以我认为它应该仍然是被接受的答案.虽然解释引擎盖下发生的事情从来没有伤害过;) (4认同)
  • @Tomalak:谁说它使用`toString()`? (3认同)
  • @Ignacio.实际上,我错了.我没有意识到37指的是基数.对于那个很抱歉. (3认同)
  • @Robert,不,我很困惑,并认为他声称的东西不是他声称的东西.这是正确的答案.道歉. (3认同)

Lig*_*ica 118

Mozilla 告诉我们:

function parseInt 将其第一个参数转换为字符串,解析它,并返回一个整数或NaN.如果不是NaN,则返回的值将是作为指定基数(基数)中的数字的第一个参数的十进制整数表示.例如,10的基数表示从十进制数转换,8八进制,十六进制16,依此类推.对于大于10的基数,字母表中的字母表示大于9的数字.例如,对于十六进制数字(基数16),使用A到F.

规范中,15.1.2.2/1告诉我们转换为字符串是使用内置函数执行的ToString(根据9.8)产生"null"(不要混淆toString,这会产生"[object Window]"!).

所以,让我们考虑一下parseInt("null", 24).

当然,这不是一个完整的base-24数字字符串,但是"n"是:它是十进制23.

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

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

(这就是为什么parseInt(null, 23)(和更低的基数)给你NaN而不是23:"n"不在base-23系统中.)

  • 这是parseInt的非常悲惨的行为(我在想这为什么它不是设计到这些情况下的异常).我希望尽可能使用NUMBER(). (2认同)

Dav*_*nco 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.湾 如果R≠16,则让stripPrefix为false.
  • 否则,R = 0 a.设R = 10.
  • 如果stripPrefix为true,则a.如果S的长度至少为2并且S的前两个字符是"0x"或"0X",则从S中删除前两个字符并让R = 16.
  • 如果S包含任何不是radix-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可以是对数学整数的依赖于实现的近似以radix-R表示法用Z表示的值.)
  • 设number为mathInt的Number值.
  • 返回标志×数字.

注意parseInt可能只将字符串的前导部分解释为整数值; 它忽略任何不能被解释为整数表示法的一部分的字符,并且没有指出任何这样的字符被忽略.

这里有两个重要的部分.我加粗了他们两个.首先,我们必须找出其toString代表性null.我们需要Table 13 — ToString Conversions在第9.8.0节中查看该信息:

在此输入图像描述

很好,所以现在我们知道在toString(null)内部做一个'null'字符串.太好了,但它究竟如何处理在提供的基数内无效的数字(字符)?

我们看上面15.1.2.2,我们看到以下说法:

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

这意味着我们处理指定基数之前的所有数字并忽略其他所有数字.

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

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


Mik*_*uel 33

parseInt( null, 24 ) === 23
Run Code Online (Sandbox Code Playgroud)

相当于

parseInt( String(null), 24 ) === 23
Run Code Online (Sandbox Code Playgroud)

这相当于

parseInt( "null", 24 ) === 23
Run Code Online (Sandbox Code Playgroud)

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

语言规范说

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

这是确保C样式整数文字15L正确解析的部分,所以上面相当于

parseInt( "n", 24 ) === 23
Run Code Online (Sandbox Code Playgroud)

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

QED


Flo*_*ern 16

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


小智 7

parseInt使用字母数字表示,然后在base-24"n"有效,但"u"是无效字符,那么parseInt只解析值"n"....

parseInt("n",24) -> 23
Run Code Online (Sandbox Code Playgroud)

例如,试试这个:

alert(parseInt("3x", 24))
Run Code Online (Sandbox Code Playgroud)

结果将是"3".