javascript 字符串转换二进制数组_奇怪的JavaScript:map和parseInt的反常应用

024fb2715352db4a445a56d139689f67.png 作者 | Eric Tong 译者 | 刘雅梦 编辑 | 张之栋 在  J avaScrip t 中,当使用 map 和 parseInt 将字符数组转换为整数时,却出现了奇怪的现象。控制台输入 ['1', '7', '11'].map(parseInt)后,得到的结果是 [1, NaN, 3] ,而不是 [1, 7, 11] 。本文将通过解释一些相关的 JavaScript 概念,解答出现这种状况的原因。

0abfc137b40f66b27f7bf66e57f3bf1f.png

JavaScript 很奇怪。不相信吗?尝试使用 map 和 parseInt 将字符数组转换为整数。打开控制台(Chrome 上的快捷键是 F12),粘贴下面的代码,然后按回车键(或将焦点放到下面)。 我们得到的不是一个整数数组 [1, 7, 11] ,而是 [1, NaN, 3] 。 为什么呢?
['1', '7', '11'].map(parseInt);

要想了解到底发生了什么,我们首先要讨论一些 JavaScript 的概念。如果你想要一个 TLDR(Too Long; Didn’t Read:太长了,不想读),我在本文的末尾提供了一个快速总结。

真 & 假 下面是 JavaScript 中的一个简单 if-else 语句:
if (true) {
    // 此处总会运行
} else {
    // 此处不会运行到
}
在本例中,if-else 语句的条件为 true,因此它总会执行 if 块,而忽略 else 块。这是一个很简单的例子,因为 true 是一个布尔值。如果我们把一个非布尔值作为条件呢?
if ("hello world") {// 这将会运行吗?
    console.log("Condition is truthy");
} else {// 还是运行这里?
    console.log("Condition is falsy");
}

尝试在开发人员的控制台(在 Chrome 上按 F12)中运行此代码。我们会发现 if 块运行了。这是因为字符串对象“hello world”是真。

每个 JavaScript 对象要么是真,要么是假。当将它们放到布尔上下文中时,如放在 if-else 语句中,对象将根据其真实性被视为 true 或 false。那么哪些对象是真,哪些是假呢?这里有一个简单的规则:

除了 false、0、“”(空字符串)、null、undefined、及 NaN 以外, 所有值都是真。

令人困惑的是,这意味着字符串 “false” 、字符串 “0” 、空对象 {} 和空数组 [] 都是真。我们可以通过将一个对象传递到布尔函数中(例如 Boolean("0"); 中),来对其进行双重检查。

就我们的目的而言,只要记住 0 是假就足够了。

    基数    

0 1 2 3 4 5 6 7 8 9 10

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

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

十进制   二进制    十六进制
基数 =10 基数 =2 基数 =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 时,parseInt 返回 3,这对应于上表中的二进制列。

函数的参数 在 JavaScript 中,函数可以用任意数量的参数来调用,即使该数量不等于声明函数时参数的数量。缺少的参数将被视为未定义,多余的参数将被忽略(但是它们会被存储在类似数组的参数对象中: https://javascriptweblog.wordpress.com/2011/01/18/javascripts-arguments-object-and-beyond/)。
function foo(x, y) {
    console.log(x);
    console.log(y);
}
foo(1, 2); // log 输出 1, 2
foo(1); // log 输出 1, undefined
foo(1, 2, 3); // log 输出 1, 2
map()

到了我们要讲的部分了!

Map 是数组原型中的一个方法,它返回一个新的数组,其中包含将原始数组的每个元素传递到函数中的结果。例如,下面的代码将数组中的每个元素乘以 3:
function multiplyBy3(x) {return x * 3;
}const result = [1, 2, 3, 4, 5].map(multiplyBy3);console.log(result); // log 输出 [3, 6, 9, 12, 15];
现在,假设我想使用 map() 记录每个元素(没有返回语句)。我应该可以将 console.log 作为参数传递到 map() 中…... 对吧?
[1, 2, 3, 4, 5].map(console.log);

ef2d1da6bf8668e323352114d273e053.png

发生了一件非常奇怪的事情。每个 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 。如果提供的基数为假,那么默认情况下,基数将被设置为 10。
parseInt('11');                => 11parseInt('11', 2);             => 3parseInt('11', 16);            => 17parseInt('11', undefined);     => 11 (基数为假)parseInt('11', 0);             => 11 (基数为假)
现在让我们一步一步地运行我们的示例。
['1', '7', '11'].map(parseInt); => [1, NaN, 3]
第一次第一次迭代 index = 0, array = ['1', '7', '11']
parseInt('1', 0, ['1', '7', '11']); => 1
因为 0 是假,所以基数设置为默认值 10。parseInt() 只接受两个参数,因此会忽略第三个参数 ['1', '7', '11'] 。以 10 为基数的字符串 '1' 表示数字 1。
// 第二次迭代 index = 1, array = ['1', '7', '11']
parseInt('7', 1, ['1', '7', '11']); => NaN
在基数为 1 的系统中,符号 '7' 不存在。与第一次迭代一样,最后一个参数将被忽略。因此,parseInt() 返回 NaN。
// 第三次迭代, 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 是假。

因此,下面的代码能按预期工作:
['1', '7', '11'].map(numStr => parseInt(numStr));

英文原文: https://medium.com/dailyjs/parseint-mystery-7c4368ef7b21

0ef7486accb7671de3a6c5a8273653e0.gif

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值