我在摆弄parseInt,看看它如何处理尚未初始化的值,我偶然发现了这个宝石。下面的情况发生在任何基数24或以上。

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]: 33,31:714695, 32:785077, 33:859935,34:939407,35:1023631, 36:1112745


博士tl;

解释为什么parseInt(null, 24) === 23是一个真语句。


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)。

当然,这不是一个以24为基底的数字字符串,但“n”是:它是十进制23。

现在,在取出十进制23之后,解析就会停止,因为“u”在以24为进制的系统中找不到:

如果S包含任意一个字符 不是基数r,则设Z为 S的子串,由所有组成 第一个字符之前的字符 字符;否则,设Z为s。[15.1.2.2/11]

(这就是为什么parseInt(null, 23)(和更低的基)给你NaN而不是23:“n”不在以23为基数的系统中。)


它正在将null转换为字符串"null"并尝试转换它。对于0到23的基数,没有可以转换的数字,所以它返回NaN。在24时,第14个字母“n”被添加到数字系统中。在第31处,第21个字母“u”被添加,整个字符串就可以解码了。在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

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


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。

语言规范说

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

这是确保像15L这样的c风格整数字面量正确解析的部分, 所以上面等价于

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

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

Q.E.D.


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

parseInt("n",24) -> 23

举个例子,试试这个:

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

结果将是“3”。


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

从15.1.2.2 parseInt(字符串,基数):

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.

这里有两个重要的部分。我把它们都加粗了。首先,我们要找出null的toString表示是什么。我们需要查看9.8.0节中的表13 - ToString转换来获取信息:

很好,现在我们知道在内部做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)同义。:)

不管怎样,问得好!