为了保证可读性,本文采用音译而非直译。

Javascript 一直是神奇的语言。 不相信我? 尝试使用mapparseInt将字符串数组转换为整数。打开 Chrome 的控制台(F12),粘贴以下内容,然后按回车,查看输出结果:

['1', '7', '11'].map(parseInt);

我们得到的不是一个整数数组[1,7,11],而是[1,NAN, 3],要了解究竟发生了什么,我们首先要讨论一些Javascript概念。

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!

真值(truthy) & 虚值(falsy)

以下是 JS 中一个简单的if-else语句:

if (true) {    // this always runs} else {    // this never runs}

在上例中,if 条件为 true,因此总是执行if块,忽略else块。这是一个简单的例子,因为true是一个布尔值。如果我们把非布尔值作为条件呢 ?

if ("hello world") {    console.log("Condition is truthy");} else {    console.log("Condition is falsy");}  

打开控制台并运行上述代码,会打印 Condition is truthy,说明条件 "hello world"真(true)值。

在 JavaScript 中,Truthy (真值)指的是在 布尔值 上下文中转换后的值为真的值。所有值都是真值,除非它们被定义为 falsy (即除了 false0""nullundefinedNaN 外)。

falsy(虚值)是在 Boolean 上下文中已认定可转换为‘假‘的值。

JS中的对象不是真值就是虚值。

令人困惑的是,这意味着字符串“false”,字符串“0”,空对象{}和空数组[]都是真的。 使用使用 Boolean 方法来验证,如 Boolean("0")

出于我们的目的,接下来只要记住0是假的就行了。

基数

在数学上,基数(cardinal number)是集合论中刻画任意集合大小的一个概念。两个能够建立元素间一一对应的集合称为互相对等集合。例如3个人的集合和3匹马的集合可以建立一一对应,是两个对等的集合。

0 1 2 3 4 5 6 7 8 9 10

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

基数是最小的数字,只能由多个符号表示。 不同的计数系统具有不同的基数,因此,相同的数字在不同的计数系统中可以表示不同的数字。

十进制   二进制    十六进制RADIX=10  RADIX=2   RADIX=160         0         01         1         12         10        23         11        34         100       45         101       56         110       67         111       78         1000      89         1001      910        1010      A11        1011      B12        1100      C13        1101      D14        1110      E15        1111      F16        10000     1017        10001     11

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

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

函数参数

JS 中函数调用,我们可以传入任意的参数,即使它们不等于声明时的函数参数的数量。缺少的参数被视为undefined 的,并且会忽略额外的参数,但会保存在类似数组的arguments对象中。

function foo(x, y) {    console.log(x);    console.log(y);}foo(1, 2);      // 打印 1, 2foo(1);         // 打印 1, undefinedfoo(1, 2, 3);   // 打印 1, 2    

map()

map是 Es6 中新出的一个数组方法,它是一个高阶函数,通过传入一个函数进行逻辑操作,并返回一个数组, 例如,以下代码将数组中的每个元素乘以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];

现在,将console.log作为参数传给 map,来打印数组的元素:

[1, 2, 3, 4, 5].map(console.log);等价于  [1, 2, 3, 4, 5].map((val, index, array) =>      console.log(val, index, array));

所以 map 回调方法中会传入三个参数,分别是 当前遍历的项,当前索引,及遍历的整个数组。

原因

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

parseInt('11');                => 11parseInt('11', 2);             => 3parseInt('11', 16);            => 17parseInt('11', undefined);     => 11 (radix is falsy)parseInt('11', 0);             => 11 (radix is falsy)

现在一步一步解析开头的事例。

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

因为0是虚值,基数设置为默认值10parseInt()只接受两个参数,因此忽略了第三个参数['1'、'7'、'11']。以10为基数的字符串“1”表示数字1

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

在基数1系统中,符号“7”不存在。与第一次迭代一样,忽略最后一个参数。因此,parseInt()返回NaN

 // Third iteration: val = '11', index = 2, array = ['1', '7', '11']parseInt('11', 2, ['1', '7', '11']);   => 3

在基数2(二进制)系统中,符号“11”表示数字3

至此原因已经明了了。 有兴趣可以试着写下下列的打印结果:

['1', '7', '11'].map(numStr => parseInt(numStr));

## 交流

干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。

https://github.com/qq44924588...

我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,即可看到福利,你懂的。