js 打印数组_JS 中为啥 「'1', '7', '11'」.map(parseInt) 返回 「1, NaN, 3」

译者:前端小智 原文:https://medium.com/dailyjs/parseint-mystery-7c4368ef7b21

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

32e9caca09771127022acdcf98f7ea22.png

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

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

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

真值(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");} 

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

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

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时,我们需要两个不同的符号( 1和 0)来表示这个数字。这是因为我们的十进制计数系统的基数是 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));
af4cc3534fadeb2973f7f7807ff996c7.png

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

原因

ParseInt有两个参数: string和 radix。 如果提供的基数是虚值,则默认情况下,基数设置为 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是虚值,基数设置为默认值 10。 parseInt()只接受两个参数,因此忽略了第三个参数 ['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));

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值