JavaScript map 的奇怪行为

4

我正在解决Codewars上的一些问题,并尝试将一个字符串转换为数字列表,如下所示:

"102904".split("").map(parseInt);

预期结果应该是这样的:
[1, 0, 2, 9, 0, 4]

但实际上它返回:

[1, NaN, NaN, NaN, 0, 4]

我认为应将map应用于列表中的每个元素,这些元素均为1位数字的字符串。有人可能认为它无法正确解析是因为未使用基数,但实际上:

"102904".split("").map(function(x){ return parseInt(x);});
[ 1, 0, 2, 9, 0, 4]

使用parseInt(x, 10)并不会改变结果,但是直接将parseInt传递给map会导致结果为NaN...

我在Chrome和Firefox上尝试了这个方法,得到了相同的结果。


1
我不确定你在问什么。"102904".split("").map(function(x){ return parseInt(x);}); 在 Chrome 30 中似乎返回了预期的结果。 - Jasper
是的,我想删除它,但是SO告诉我不能这样做... - Loïc Faure-Lacroix
3个回答

7

parseInt 函数包含第二个参数 - 基数。

你的问题在于 - map 方法会传递两个参数: 项目本身和索引。

有问题的数字是: 0, 2, 9

为什么呢?

  • 0 - 使用基数1进行解析,1不是有效的进制数,因此返回NaN
  • 2 - 使用基数2进行解析,2进制中没有数字2(只有0和1)
  • 9 - 使用基数3进行解析,3进制中没有数字9(只有0, 1, 2)

1
"102904".split("").map(function(x, y){ console.log(x, y) });

返回
1 0
0 1
2 2
9 3
0 4
4 5

这意味着,在您的第一个示例中,parseInt 被这样调用:
parseInt("1", 0);
parseInt("0", 1);
parseInt("2", 2);
parseInt("9", 3);
// ecc...

你正在将迭代的索引作为第二个参数传递给 parseInt() (它表示要解析的数字的基数)。
最佳解决方案是使用第二种方法,使用您已经发布的代码。

是的,我当时在厨房里意识到 JavaScript 与其他函数式语言不同,它会向 map 函数发送多个参数。 - Loïc Faure-Lacroix

1

作为回调函数提供给 Array.prototype.map 的函数会接收到三个参数:

  • 数组中的元素
  • 数组中的索引
  • 数组本身

如果你向 parseInt 提供两个参数,则第二个参数将被视为基数 - 解析数字所使用的数值基数。因此,你的字符串将被解析为:

string | base | result
----------------------
1      | 0    | 1
0      | 1    | NaN
2      | 2    | NaN
9      | 3    | NaN
0      | 4    | 0
4      | 5    | 4

这里的令人惊讶的行为是,使用基数0(不可能的情况下),结果是1而不是NaN。这是因为parseInt将基数0视为未提供:

如果基数未定义或为0(或缺失),JavaScript会假设以下内容:(MDN文档)


是的,我忘了那个map函数会发送3个参数。 - Loïc Faure-Lacroix

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