本篇文章采用意译,原文地址数组
你有没有以为 Javascript 是有点奇怪的。使用 map
和 parseInt
试着把字符串数组转化成整型数组,看看会发生什么。打开你的控制台,粘贴下面的代码而后执行。bash
['1', '7', '11'].map(parseInt);
复制代码
没有获得 [1,7,11
,却获得了 [1, NaN, 3]
。这到底是怎么回事?咱们首先须要讨论一些 Javascript 的概念,若是你以为太长,能够跳到最后看总结。函数
一个简单的 if-else 语句:ui
if (true) {
// this always runs
} else {
// this never runs
}
复制代码
在这个例子中,条件为真,执行 if 的语句块,条件为假执行 else 的语句块。这是显而易见的,由于 true 是个布尔值。咱们把非布尔值的东西做为条件,会发生什么?this
if ("hello world") {
// 它会运行吗?
console.log("Condition is truthy");
} else {
// 它呢?
console.log("Condition is falsy");
}
复制代码
在控制台里运行上面的代码,你会发现 if 语句块执行了。由于这个字符串对象是真值。spa
Javascript 对象要么是真值要么是假值。当在布尔值上下文中,好比 if-else 语句,对象被当作真或者假取决于它们的真实性。这个规则很简单:日志
除了:false, 0, ""(空字符串),null, undefined, 和 NaN
以外,其余的都是真值。code
使人困惑的是,字符串 "false" 和 字符串 "0" 还有空对象 {}, 空数组 [],都是真值。你能够经过给布尔函数传值来进行双向验证,好比 Boolean("0")
。cdn
咱们的目的是,知道 0 是假值就足够了。对象
0 1 2 3 4 5 6 7 8 9 10
复制代码
当咱们从 0 数到 9 的时候,每一个不一样的符号表明一个数字。然而到 10 的时候,咱们须要两个符号来表示。这是由于咱们是十进制系统,它的基数是 10.
基数是用一个以上的符号表示的最小数字。不一样的计数系统有着不一样的基数。
DECIMAL BINARY HEXADECIMAL
RADIX=10 RADIX=2 RADIX=16
0 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 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
16 10000 10
17 10001 11
复制代码
看看上面的表,数字 11 在不一样的系统中表示也不一样。若是基数是 2,它是 3,若是基数是 16,它是 17.
咱们上面的例子中吧 '11' 转换成了 3,就是上面表格二进制的表现。
Javascript 中的函数能够传递任意数量的参数,即便跟函数声明的参数不相等。缺乏的参数会被当作 undefined,多余的参数会被忽略(可是会存储在类数组的 arguments 对象中)。
function foo(x, y) {
console.log(x);
console.log(y);
}
foo(1, 2); // logs 1, 2
foo(1); // logs 1, undefined
foo(1, 2, 3); // logs 1, 2
复制代码
立刻就到咱们的重点了!
Map 是 Array 原型上的方法,它返回一个每一个原始数组的元素传入函数的结果的新数组。好比下面代码,每一个元素在数组中乘 3:
function multiplyBy3(x) {
return x * 3;
}
const result = [1, 2, 3, 4, 5].map(multiplyBy3);
console.log(result); // logs [3, 6, 9, 12, 15];
复制代码
那么如今若是我须要日志输出每一个元素,是否是使用 map()
而后传入 console.log
就能够了呢?
[1, 2, 3, 4, 5].map(console.log);
复制代码
奇怪的事,不仅是输出了值,同时把索引和所有数组也输出了。
[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()
传入一个方法时,对于每次迭代,都会有三个参数传入方法:currentValue, currentIndex,
和所有 array
。这就是为何每次迭代都会输出所有三个实体内容。
如今离解开咱们的谜题愈来愈近了。
ParseInt
接受两个参数:string
和 radix
。若是 radix 没有提供,默认值就是 10.
parseInt('11'); => 11
parseInt('11', 2); => 3
parseInt('11', 16); => 17
parseInt('11', undefined); => 11 (没有 radix)
parseInt('11', 0); => 11 (没有 radix)
复制代码
如今一步步走进以前的例子:
['1', '7', '11'].map(parseInt); => [1, NaN, 3]
// 第一次遍历: val = '1', index = 0, array = ['1', '7', '11']
parseInt('1', 0, ['1', '7', '11']); => 1
复制代码
由于 0 是假值,因此 radix 基数取值为 10。 由于 parseInt 只接受两个参数,因此第三个 ['1', '7', '11']
参数被忽略了。
// 第二次遍历: val = '7', index = 1, array = ['1', '7', '11']
parseInt('7', 1, ['1', '7', '11']); => NaN
复制代码
由于在基数为 1 的系统中, 7
不存在。同时第三个参数仍然跟第一次迭代同样被省略。因此 parseInt()
返回了 NaN
。
// 第三次迭代: val = '11', index = 2, array = ['1', '7', '11']
parseInt('11', 2, ['1', '7', '11']); => 3
复制代码
基数为 2 的系统中, 符号 11
得出数字 3。最后的参数被省略。
['1', '7', '11'].map(parseInt)
没有像预期那样工做,是由于 map 给 parseInt 传递了三个参数。第二个参数 index 做为 radix 参数传入了 parseInt。因此每一个数组的字符串使用了不一样的基数来解析。'7' 被解析为基数为 1 的结果,也就是 NaN,11
被解析为基数为 2 的结果,也就是 3。1
被做为默认值解析,由于索引 0 是假值。因此,下面的代码才能正常工做:
['1', '7', '11'].map(numStr => parseInt(numStr));
复制代码