不稳定的NaN映射parseInt

20

我在尝试创建一个由0组成的数组的代码时发现,仅有一个值返回的是NaN而非0。这在Chrome,Node和Firefox中都出现了。

是什么导致第二个值变成了NaN

var arr = new Array(32).join(0).split('').map(parseInt)
// prints [0, NaN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
console.dir(arr)

3
你尝试过使用 new Array(32).fill(0); 吗? - user5283155
1
您可能会对创建零填充JavaScript数组的最有效方法?感兴趣。 - Oriol
3个回答

26
那是因为传递给 map 的函数将被调用三个参数:
  1. 当前的数组项
  2. 该项的索引
  3. 整个数组

在这种情况下,该函数是parseInt,它只使用两个参数:

  1. 要解析的字符串
  2. 用于解析字符串的基数
  3. 其他参数将被忽略。

因此,对于数组中的第二个项目(即索引1),调用将为

parseInt("0", 1, ignoredArray)

当基数为1时,将返回NaN

  • R = ToInt32(radix)。
  • 如果R ≠ 0,则
    • 如果R < 2或R > 36,则返回NaN

还要注意,如果您使用一个更大的数字,例如new Array(99),则会在索引37处看到NaN


然而0是一个有效的基数? - user253751
如果实际需要解析整数字符串数组,最简单的解决方案是使用parseFloat,它只需要一个参数。 - Mihai
@immibis 从数学上讲,0进制没有意义。因此,如果您使用0,JS将假定您的意思是10。 - Oriol

9
.map()函数将三个参数传递给回调函数,其中两个参数由parseInt()使用:值和索引(第三个参数为数组本身)。当索引为1时,任何数字字符串都将是无效的值。当第二个参数为0时,parseInt()函数会忽略第二个参数。
详细说明:对于第一个元素,parseInt()的调用方式如下:
parseInt("0", 0)

因为数组的值为零且索引为零。在第二次调用时,是这样的:
parseInt("0", 1)

这会返回NaN

请注意,如果您对结果不是整数不太挑剔,您可以使用Number构造函数来完成您想要的操作:

var arr = new Array(32).join(0).split('').map(Number);

在ES2015中(JavaScript的最新标准,如果我们都很好的话,将作为圣诞礼物完全实现在所有浏览器中),你可以使用.fill()函数:

var arr = new Array(31).fill(0);

6
三个参数,第三个参数是你正在映射的数组。parseInt 忽略第三个参数。 - user2357112
@user2357112 是的,那是真的,而且是的 parseInt 只查看它的前两个参数。 - Pointy

7

该映射将三个参数传递给其函数:

  • 元素;
  • 该元素在数组中的索引; 和
  • 数组本身。

parseInt函数将查看前两个参数,将第一个正确地视为字符串,但将第二个参数视为要使用的基数。当基数既不为零也不在包括范围2..36内时,它将返回NaN (1)。如果您有一个四十个元素的数组,您还会看到一堆NaN值:

0, NaN, 0, 0, 0, ... 0, 0, 0, NaN, NaN

如果数字字符串不是零,那么数组索引将决定使用哪个基数进行解释,因此你会得到一些非常奇怪的结果。

要真正解决这个问题,你可以提供一个函数,将map给你的内容转换为parseInt期望的内容(我想你可以称之为映射映射):

function myParseInt(s,r,a) { return parseInt(s,10); }
var arr = new Array(32).join(0).split('').map(myParseInt)
alert(arr)

您可能也想看一下您创建该数组的方式,它实际上会以一个大小为31而不是32的数组结束。如果您只想要一个由'0'字符组成的数组,您可以使用以下代码:

var arr = new Array(32).fill('0')

假设您使用支持 ECMAScript 2015 的浏览器,这包括 Safari、Firefox 和 Chrome-desktop(截至本回答时)。

(1) 基数为零是处理十六进制前缀等情况的默认情况。

基数为一在纯位置制中没有意义(其中每个数字都乘以基数的幂并累加),因为唯一允许的数字是 0,所以每个位值将是该零乘以 1n。换句话说,在基数为一的系统中唯一可能的数字是零。

因此,从基数 236 更加合理。


你说基数为1不可行,因为唯一的数字将是1^n,实际上基数为1的位数与数字一样多(即30=1.......1三十次)。对基数为1的数字进行运算非常冗长,特别是打印基数为1的数字可能需要打印大量的1,这并不是很有信息量。当然,这是一种约定,并且也有需要证明基数为1的定理(例如,一个3个寄存器的机器是图灵完备的)。 - CoffeDeveloper
1
@DarioOO,基数1只有数字0(不是1),就像基数2只有01一样。在纯粹的位值制中,该0只能生成零,因为给定位置n的值将为0 x 1^n。换句话说,无论你有多少位数字,00000...000都是零。基数1可能对于非位值制是可行的,所以我会明确表明我的意思。 - paxdiablo
这是因为您扩展了适用于基于2+数字的定义,它通常是由1而不是0组成的数字: https://en.wikipedia.org/wiki/Unary_numeral_system 这并不是一个数字基数的唯一定义,存在着具有无一元基数的通用定义。 - CoffeDeveloper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接