关于javascript:parseInt(null,24)=== 23 …等等,什么?

parseInt(null, 24) === 23… wait, what?

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

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

我在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是一个真实的陈述。


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

1
2
3
4
5
js> parseInt(null, 36)
1112745

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


Mozilla告诉我们:

function parseInt converts its first
argument to a string, parses it, and
returns an integer or NaN. If not NaN,
the returned value will be the decimal
integer representation of the first
argument taken as a number in the
specified radix (base). For example, a
radix of 10 indicates to convert from
a decimal number, 8 octal, 16
hexadecimal, and so on. For radices
above 10, the letters of the alphabet
indicate numerals greater than 9. For
example, for hexadecimal numbers (base
16), A through F are used.

在规范中,15.1.2.2/1告诉我们使用内置的ToString执行到字符串的转换,其中(按照9.8)产生"null"(不要与ToString混淆,否则会产生"[object Window]"!)。

那么,让我们考虑一下parseInt("null", 24)

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

现在,在拉出小数23之后解析停止,因为在base-24系统中找不到"u"

If S contains any character that is
not a radix-R digit, then let Z be the
substring of S consisting of all
characters before the first such
character; otherwise, let Z be S. [15.1.2.2/11]

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


Ignacio Vazquez-Abrams是正确的,但让我们看看它是如何工作的......

来自15.1.2.2 parseInt (string , radix)

When the parseInt function is called,
the following steps are taken:

  • Let inputString be ToString(string).
  • Let S be a newly created substring of inputString consisting of the first
    character that is not a
    StrWhiteSpaceChar and all characters
    following that character. (In other
    words, remove leading white space.)
  • Let sign be 1.
  • If S is not empty and the first character of S is a minus sign -, let
    sign be ?1.
  • If S is not empty and the first character of S is a plus sign + or a
    minus sign -, then remove the first
    character from S.
  • Let R = ToInt32(radix).
  • Let stripPrefix be true.
  • If R ≠ 0, then a. If R < 2 or R > 36, then return NaN. b. If R ≠ 16, let
    stripPrefix be false.
  • Else, R = 0 a. Let R = 10.
  • If stripPrefix is true, then a. If the length of S is at least 2 and the
    first two characters of S are either
    "0x" or"0X", then remove the first
    two characters from S and let R = 16.
  • If S contains any character that is not a radix-R digit, then let Z be the
    substring of S consisting of all
    characters before the first such
    character; otherwise, let Z be S.
  • If Z is empty, return NaN.
  • Let mathInt be the mathematical integer value that is represented by Z
    in radix-R notation, using the letters
    A-Z and a-z for digits with values 10
    through 35. (However, if R is 10 and Z
    contains more than 20 significant
    digits, every significant digit after
    the 20th may be replaced by a 0 digit,
    at the option of the implementation;
    and if R is not 2, 4, 8, 10, 16, or
    32, then mathInt may be an
    implementation-dependent approximation
    to the mathematical integer value that
    is represented by Z in radix-R
    notation.)
  • Let number be the Number value for mathInt.
  • Return sign × number.

NOTE parseInt may interpret only a
leading portion of string as an
integer value; it ignores any
characters that cannot be interpreted
as part of the notation of an integer,
and no indication is given that any
such characters were ignored.

这里有两个重要的部分。我加粗了他们两个。首先,我们必须找出nullToString表示是什么。我们需要在9.8.0节中查看Table 13 — ToString Conversions以获取该信息:

enter image description here

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

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

If S contains any character that is
not a radix-R digit, then let Z be the
substring of S consisting of all
characters before the first such
character; otherwise, let Z be S.

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

基本上,执行parseInt(null, 23)parseInt('null', 23)是一回事。 u导致忽略两个l(即使它们是基数23的一部分)。因此,我们只能解析n,使整个语句与parseInt('n', 23)同义。 :)

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


1
parseInt( null, 24 ) === 23

相当于

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

这相当于

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

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

语言规范说

  • If S contains any character that is not a radix-R digit, then let Z be the substring of S consisting of all characters before the first such character; otherwise, let Z be S.
  • 这是确保像15L这样的C风格整数文字正确解析的部分,
    所以上面相当于

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

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

    证明完毕


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


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

    1
    parseInt("n",24) -> 23

    例如,试试这个:

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

    结果将是"3"。