前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript注意点:Array.prototype.map

JavaScript注意点:Array.prototype.map

原创
作者头像
Jean
修改2021-11-11 22:04:29
1.1K0
修改2021-11-11 22:04:29
举报
文章被收录于专栏:Web行业观察

为什么 [ '1 ', '7 ', '11 '].map(parseInt) 在 Javascript 中返回 [1, NaN, 3]?

简单结论:因为map传递3个参数,parseInt接收2个参数,额外的参数导致了出错。如果是parseFloat就没问题了,因为parseFloat只接受1个参数。

???

JavaScript 很奇怪。不相信我?尝试使用 map 和 parseInt 将字符串数组转换为整数。启动您的控制台(Chrome 上的 F12),粘贴以下内容,然后按 Enter(或运行下面的笔)。

代码语言:javascript
复制
['1', '7', '11'].map(parseInt);

我们没有给我们一个整数数组[1, 7, 11],而是以[1, NaN, 3]. 什么?要了解到底发生了什么,我们首先必须讨论一些 Javascript 概念。如果你想要一个 TLDR,我在这个故事的结尾包含了一个简短的总结。

真与假

这是 Javascript 中的一个简单的 if-else 语句:

代码语言:javascript
复制
if (true) { 
    // 这总是运行
} else { 
    // 这永远不会运行
}

在这种情况下,if-else 语句的条件为真,所以总是执行 if-block 而忽略 else-block。这是一个简单的例子,因为 true 是一个布尔值。如果我们把一个非布尔值作为条件呢?

代码语言:javascript
复制
if ("hello world") { 
    // 这会运行吗?
    console.log("条件为真"); 
} else { 
    // 还是这个?
    console.log("条件为假"); 
}

尝试在开发人员的控制台中运行此代码(Chrome 上为 F12)。您应该会发现 if 块运行。这是因为字符串对象"hello world"是真实的。

每个 Javascript 对象要么是真的,要么是假的。当放置在布尔上下文中时,例如 if-else 语句,对象会根据其真实性被视为真或假。那么哪些对象是真的,哪些是假的呢?这是一个简单的规则:

所有值都是真实的,除了: false, 0, "" (空字符串), null, undefined, 和 NaN.

令人困惑的是,这意味着字符串"false"、字符串"0"、空对象{}和空数组[]都是真值。您可以通过将对象传递给布尔函数(例如Boolean("0");)来仔细检查这一点。

为了我们的目的,记住这0是假的就足够了。

基数

代码语言:javascript
复制
0 1 2 3 4 5 6 7 8 9 10

当我们从零数到九时,每个数字(0-9)都有不同的符号。但是,一旦达到十,我们就需要两个不同的符号(1 和 0)来表示数字。这是因为我们的十进制计数系统的基数(或基数)为 10。

基数是最小的数,只能用一个以上的符号表示。不同的计数系统有不同的基数,因此,相同的数字在计数系统中可以指代不同的数字。

代码语言:javascript
复制
十进制二进制十六进制
基数=10基数=2基数=160 0 0 
1 1 1 
2 10         2 
3          11         3 
4 100 4 
5 101 5 
6 110 6 
7 111 7 
8 1000 8 
9 1001 9 
10 1010甲
11         1011乙
12 1100℃ 
13 1101 d 
14 1110ë 
15 1111˚F 
16万10 
17 10001      11

例如,查看上表,我们看到相同的数字 11 在不同的计数系统中可能表示不同的数字。如果基数是 2,那么它指的是数字 3。如果基数是 16,那么它指的是数字 17。

您可能已经注意到,在我们的示例中,当输入为 11 时,parseInt 返回 3,这对应于上表中的 Binary 列。

函数参数

可以使用任意数量的参数调用 Javascript 中的函数,即使它们不等于声明的函数参数的数量。缺少的参数被视为未定义,额外的参数将被忽略(但存储在类似数组的参数对象中)。

代码语言:javascript
复制
函数 foo(x, y) { 
    console.log(x); 
    控制台日志(y);
}foo(1, 2); // 记录 1, 2 
foo(1); // 记录 1, 未定义
foo(1, 2, 3); // 记录 1, 2

地图()

我们快到了!

Map 是 Array 原型中的一个方法,它返回将原始数组的每个元素传递给函数的结果的新数组。例如,以下代码将数组中的每个元素乘以 3:

代码语言:javascript
复制
函数乘以3(x){
    返回x * 3; 
}const 结果 = [1, 2, 3, 4, 5].map(multiplyBy3);控制台日志(结果);// 记录 [3, 6, 9, 12, 15];

现在,假设我想使用map()(没有返回语句)记录每个元素。我应该能够console.log作为参数传递给map()……对吧?

代码语言:javascript
复制
[1, 2, 3, 4, 5].map(console.log);

一些非常奇怪的事情正在发生。不是只记录值,每次console.log调用还记录索引和完整数组。

代码语言:javascript
复制
[1, 2, 3, 4, 5].map(console.log);// 上面等价于[1, 2, 3, 4, 5].map( 
    (val, index, array) => console.log(val, index, array) 
);// 不等价于[1, 2, 3, 4, 5].map( 
    val => console.log(val) 
);

当一个函数传递到map(),对于每次迭代,三个参数传递到函数currentValuecurrentIndex,和完整的array。这就是为什么每次迭代都记录三个条目的原因。

我们现在拥有解开这个谜团所需的所有碎片。

把它放在一起

ParseInt 有两个参数:stringradix。如果提供的基数为假,则默认情况下基数设置为 10。

代码语言:javascript
复制
parseInt('11'); => 11 
parseInt('11', 2); => 3 
parseInt('11', 16); => 17parseInt('11', 未定义); => 11 (基数为假) 
parseInt('11', 0); => 11(基数为假)

现在让我们逐步运行我们的示例。

代码语言:javascript
复制
['1', '7', '11'].map(parseInt); => [1, NaN, 3]// 第一次迭代:val = '1', index = 0, array = ['1', '7', '11']parseInt('1', 0, ['1', '7', '11']); => 1

由于 0 为假,因此基数设置为默认值 10。parseInt()仅接受两个参数,因此['1', '7', '11']忽略第三个参数。'1'基数 10 中的字符串指的是数字 1。

代码语言:javascript
复制
// 第二次迭代:val = '7', index = 1, array = ['1', '7', '11']parseInt('7', 1, ['1', '7', '11']); => NaN

在基数为 1 的系统中,该符号'7'不存在。与第一次迭代一样,最后一个参数被忽略。所以,parseInt()返回NaN

代码语言:javascript
复制
// 第三次迭代:val = '11', index = 2, array = ['1', '7', '11']parseInt('11', 2, ['1', '7', '11']); => 3

在基数 2(二进制)系统中,符号'11'指的是数字 3。最后一个参数被忽略。

摘要 (TLDR)

['1', '7', '11'].map(parseInt)无法按预期工作,因为在每次迭代中map传递了三个参数parseInt()。第二个参数index作为radix参数传递给 parseInt 。因此,数组中的每个字符串都使用不同的基数进行解析。'7'解析为基数 1,即NaN'11'解析为基数 2,即 3。'1'解析为默认基数 10,因为其索引 0 为假。

因此,以下代码将按预期工作:

代码语言:javascript
复制
['1', '7', '11'].map(numStr => parseInt(numStr));

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么 [ '1 ', '7 ', '11 '].map(parseInt) 在 Javascript 中返回 [1, NaN, 3]?
  • 真与假
  • 基数
  • 函数参数
  • 地图()
  • 把它放在一起
  • 摘要 (TLDR)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档