第 2 题:['1', '2', '3'].map(parseInt) what & why ?

发布于 2022-06-29 17:00:27 字数 1186 浏览 1215 评论 41

第一眼看到这个题目的时候,脑海跳出的答案是 [1, 2, 3],但是真正的答案是 [1, NaN, NaN]

首先让我们回顾一下,map 函数的第一个参数 callback:

var new_array = arr.map(function callback(currentValue[, index[, array]]) { 
// Return element for new_array
}[,  thisArg])

这个 callback 一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。

而 parseInt 则是用来解析字符串的,使字符串成为指定基数的整数。

parseInt(string, radix)

接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。

了解这两个函数后,我们可以模拟一下运行情况

  1. parseInt('1', 0) // radix 为 0 时,且 string 参数不以 0x 和 0 开头时,按照 10 为基数处理。这个时候返回 1
  2. parseInt('2', 1) // 基数为 1(1 进制)表示的数中,最大值小于 2,所以无法解析,返回 NaN
  3. parseInt('3', 2) // 基数为 2(2 进制)表示的数中,最大值小于 3,所以无法解析,返回 NaN

map 函数返回的是一个数组,所以最后结果为 [1, NaN, NaN]

最后附上MDN上对于这两个函数的链接,具体参数大家可以到里面看

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/parseInt
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(41

浅笑轻吟梦一曲 2022-05-04 13:57:52

['1', '2', '3'].map(parseInt)等价于[parseInt('1',0), parseInt('2',1), parseInt('3',2)]

娇柔作态 2022-05-04 13:57:52

总之 radix在[2-9]区间内 Number(string.charAt(0)) 不能大于等于 radix
0x和0X开头的默认都是 16进制字符串转10进制 如果指定了radix 那么都是按常规字符串处理=>0

-梦年海沫深 2022-05-04 13:57:52

基数为1(1进制)的时候,返回的结果都是NaN,所以parseInt('2', 1)返回结果是NaN
基数为2(2进制)的时候,字符串的值要求是0和1,所以parseInt('3', 2)返回结果是NaN

忆梦 2022-05-04 13:57:52

根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:

> ['1','2','3'].map(n=>parseInt(n,10))
<- [1, 2, 3]

当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措

> ['1','2','3'].map(n=>parseInt(n))
<- [1, 2, 3]
情丝乱 2022-05-04 13:57:52

其实这个可以用函数式思维来解决,具体可以看月影老师写的这篇博文

人生戏 2022-05-04 13:57:52

parseInt('11', "4") 这个为啥等于5呢,他4进制,11应该也不在其范围内么,怎么会得出的结果为5呢

蛮可爱 2022-05-04 13:57:52

parseInt('11', "4") 这个为啥等于5呢,他4进制,11应该也不在其范围内么,怎么会得出的结果为5呢

'11'表示的是4进制的数啊 5 是十进制 1=>1 2=>2 3=>3 10=>4 11=>5
没有包含大于三的数字 就可以 懂了吗

二手情话 2022-05-04 13:57:52

parseInt('11', "4") 这个为啥等于5呢,他4进制,11应该也不在其范围内么,怎么会得出的结果为5呢

第一步,“11”以非"0x" or "0X" or "0" 开头,“11”转为数字11,即parseInt(11, "4")。
第二步, 基数是4,表示4进制,11表示4进制的数,parseInt转换4进制数11为10进制,4^0 + 4^1 = 5。 总结:parseInt('11', "4") 输出为10进制5。

看海 2022-05-04 13:57:52

明白了,谢谢

述情 2022-05-04 13:57:52

我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
你这是两个问题
第1 超出2-36这个范围的有一个特殊数字0是允许的。如果是0则看字符串是否以0x,0开头,若以0x开头解析成16进制,0开头以前有版本解析成8进制,现在的规范基本都解析成10进制,还有其他的一些约束,可以看一下官方文档
第2 parseInt('5',4)为什么会返回NaN,因为4进制中只有0,1,2,3这几个数字,跟2进制中只有0,1这两个数一样。5已经超出4进制的范围了(可以用4进制来表述10进制的5),所以返回NaN

ヤ经典坏疍 2022-05-04 13:57:52

根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:

> ['1','2','3'].map(n=>parseInt(n,10))
<- [1, 2, 3]

当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措

> ['1','2','3'].map(n=>parseInt(n))
<- [1, 2, 3]

一般对我来说,在平时coding时,都是箭头函数,这点能避免很多问题的,另外 parseInt在使用时,我一般都是会加上第二个参数为10

书间行客 2022-05-04 13:57:52

根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:

> ['1','2','3'].map(n=>parseInt(n,10))
<- [1, 2, 3]

当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措

> ['1','2','3'].map(n=>parseInt(n))
<- [1, 2, 3]

一般对我来说,在平时coding时,都是箭头函数,这点能避免很多问题的,另外 parseInt在使用时,我一般都是会加上第二个参数为10

这么多答案,而且那些答案也说得有理有据,分析得非常深入
但是,还是觉得你的最正确

嘦怹 2022-05-04 13:57:52

@thinkfish 哈哈 实际应用肯定是最小减少问题,但原理了解透彻还是很有必要的嘛

薄情伤 2022-05-04 13:57:52

@thinkfish 哈哈 实际应用肯定是最小减少问题,但原理了解透彻还是很有必要的嘛

在理,至少在遇到问题的时候能快速定位

肤浅与狂妄 2022-05-04 13:57:52

在30-seconds-of-code看到一个这个题的变形,分享一下

let unary = fn => val => fn(val)
let parse = unary(parseInt)
console.log(['1.1', '2', '0.3'].map(parse))

这种方法绕过了parseInt的第二个参数,实际执行如下:
console.log(['1.1', '2', '0.3'].map( item => {
return parseInt(item)
}))
花里胡哨的。

歌枕肩 2022-05-04 13:57:52

@developement711
parseInt的第二个参数:radix参数为n 将会把第一个参数看作是一个数的n进制表示,而返回的值则是十进制
例如: parseInt('11', 4) // 将'11'看作4进制数,返回十进制数5 => 1*4^1 + 1*4^0 = 5

紫南 2022-05-04 13:57:52

首先看看 parseInt 方法在 MDN 的文档

parseInt(string, radix);

string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。

radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数 10 表示使用十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常认为其值默认为10,但是如果你的代码运行在过时的浏览器中,那么请在使用时总是显式地指定 radix。

返回值
返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN

接下来分析 map 中的每一次迭代调用 parseInt 的参数:

  1. parseInt('1', 0, ['1', '2', '3']) 输出 1
  2. parseInt('2', 1, ['1', '2', '3']) 输出 NaN
  3. parseInt('3', 2, ['1', '2', '3']) 输出 NaN

所以结果为:[1, NaN, NaN]

夕色琉璃_ 2022-05-04 13:57:52

首先看看 parseInt 方法在 MDN 的文档

parseInt(string, radix);
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。
radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数 10 表示使用十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常认为其值默认为10,但是如果你的代码运行在过时的浏览器中,那么请在使用时总是显式地指定 radix。
返回值
返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN

接下来分析 map 中的每一次迭代调用 parseInt 的参数:

1. `parseInt('1',  0, ['1', '2', '3'])` 输出 `1`

2. `parseInt('2',  1, ['1', '2', '3'])` 输出 `NaN`

3. `parseInt('3',  2, ['1', '2', '3'])` 输出 `NaN`

所以结果为:[1, NaN, NaN]

谢谢回答,但是我想请问的是关于那个变形题的答案

let unary = fn => val => fn(val)
let parse = unary(parseInt)
console.log(['1.1', '2', '0.3'].map(parse))

这个的答案能否解释一下呢?

想念有你 2022-05-04 13:57:52

在30-seconds-of-code看到一个这个题的变形,分享一下

let unary = fn => val => fn(val)
let parse = unary(parseInt)
console.log(['1.1', '2', '0.3'].map(parse))

这个的答案是什么呢?

我是这样理解的:

unary函数接收一个回调函数 fn ,返回一个闭包。

也就是说 parse函数等同于 let parse = val => parseInt(val)

传入 parse 函数的参数依次是(箭头函数没有 arguments所以超过形参的实参会被忽略):

  1. parse('1.1') 返回 1
  2. parse('2') 返回 2
  3. parse('0.3') 返回 0

输出 [1, 2, 0]

赠佳期 2022-05-04 13:57:52

在30-seconds-of-code看到一个这个题的变形,分享一下

let unary = fn => val => fn(val)
let parse = unary(parseInt)
console.log(['1.1', '2', '0.3'].map(parse))

这个的答案是什么呢?

我是这样理解的:

unary函数接收一个回调函数 fn ,返回一个闭包。

也就是说 parse函数等同于 let parse = val => parseInt(val)

传入 parse 函数的参数依次是(箭头函数没有 arguments所以超过形参的实参会被忽略):

1. `parse('1.1')` 返回 `1`

2. `parse('2')` 返回 `2`

3. `parse('0.3')` 返回 `0`

输出 [1, 2, 0]

谢谢回答~

扶醉桌前 2022-05-04 13:57:52

做完每一题(学习技术一定要以一手资料为主):
题目2答案:分别分析了specification里面是如何描述 parseInt 和 Array.prototype.map 的。

挽清梦 2022-05-04 13:57:52

这题的考察点有三个:

  1. Array.map方法callback函数的参数问题
  2. JS函数的实参、形参。
  3. parseInt方法的使用,其第二个参数的意思及规则

Array.map方法的callback函数接收三个参数,(value, index, array)。

而parseInt方法接收两个参数。这里就涉及到函数参数个数问题了,在JS中,不看形参的,看实参,就是你传多少个参数给我无所谓,我函数内部只用我需要的,其内部使用arguments进行引用,具体机制可以查阅相关资料文章。
比如这里的parseInt方法,虽然map的callback给它传了三个参数,但是它只会用到前两个参数,也就是map函数callback的value和index。

所以题目就转化成了如下形式:

['1', '2', '3'].map(parseInt) = [parseInt('1', 0), parseInt('2', 1), parseInt('3', 2)]

而接下来,你就要知道parseInt方法的参数意义了:

parseInt(string, radix)
参数描述
string

失而复得 2022-05-04 13:57:52

看了这个题目后专门去研究了parseInt,parseInt的参数
parseInt(String,radix)里的radix根本就没有这么简单,radix根本就不是单纯的进制,详情看我简书的文章
parseInt详解-你以为radix指的进制吗?
parseInt

浪漫人生路 2022-05-04 13:57:52

说实话,我还是没懂,为啥 ['10','10','10','10','10'].map(parseInt); => // [10, NaN, 2, 3, 4]
为啥parseInt("10",3) =>//3 ???

二进制,这里 3^1 +3^0 = 3

大哥。。。parseInt("10",3)这里的3指的是三进制。而且3^0 = 1啊。。。你的公式3^1 +3^0 那是等于4的啊。。。

森罗 2022-05-04 13:57:52

说实话,我还是没懂,为啥 ['10','10','10','10','10'].map(parseInt); => // [10, NaN, 2, 3, 4]
为啥parseInt("10",3) =>//3 ???

二进制,这里 3^1 +3^0 = 3

大哥。。。parseInt("10",3)这里的3指的是三进制。而且3^0 = 1啊。。。你的公式3^1 +3^0 那是等于4的啊。。。

3^1 +3^0 = 3是不准确的,应该说是1 * 3^1 + 0 * 3^0 = 3,前面还要乘系数的,你想一下二进制的10为什么是2就明白了

人生戏 2022-05-04 13:57:52

看了这个题目后专门去研究了parseInt,parseInt的参数
parseInt(String,radix)里的radix根本就没有这么简单,radix根本就不是单纯的进制,详情看我简书的文章
parseInt详解-你以为radix指的进制吗?
parseInt

parseInt('45', 5) //4 这个应该算是parseInt的内部处理,跟radix是不是进制数没有关系。
MDN文档上是这样写的:
如果 parseInt 遇到的字符不是指定 radix 参数中的数字,它将忽略该字符以及所有后续字符,并返回到该点为止已解析的整数值。 parseInt 将数字截断为整数值。 允许前导和尾随空格。

多情出卖 2022-05-04 13:57:52

这题的考察点有三个:

  1. Array.map方法callback函数的参数问题
  2. JS函数的实参、形参。
  3. parseInt方法的使用,其第二个参数的意思及规则

Array.map方法的callback函数接收三个参数,(value, index, array)。

而parseInt方法接收两个参数。这里就涉及到函数参数个数问题了,在JS中,不看形参的,看实参,就是你传多少个参数给我无所谓,我函数内部只用我需要的,其内部使用arguments进行引用,具体机制可以查阅相关资料文章。
比如这里的parseInt方法,虽然map的callback给它传了三个参数,但是它只会用到前两个参数,也就是map函数callback的value和index。

所以题目就转化成了如下形式:

['1', '2', '3'].map(parseInt) = [parseInt('1', 0), parseInt('2', 1), parseInt('3', 2)]

而接下来,你就要知道parseInt方法的参数意义了:

parseInt(string, radix)

参数 描述
string 必需。要被解析的字符串。
radix 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。
这是一些例子

parseInt("10");			//返回 10
parseInt("19",10);		//返回 19 (10+9)
parseInt("11",2);		//返回 3 (2+1)
parseInt("17",8);		//返回 15 (8+7)
parseInt("1f",16);		//返回 31 (16+15)
parseInt("010");		//未定:返回 10 或 8

从上面的解释可以知道:

parseInt('1', 0) = 1。

第二个参数为0,则默认基数是十,也就是'1',是十进制的数字字符串,转为数字自然就是1了。

parseInt('2', 1) = NaN。

第二个参数为1,小于2,所以值为NaN。

parseInt('3', 2) = NaN。

第二个参数为2,则说明'3'是二进制的数字字符串。然后3是个不合法的二进制(二进制有0和1组成),无法转换,所以值为NaN

所以最终的结果是:[1, NaN, NaN]

parseInt('14', 2) 

parseInt('14', 2) parseInt从参数的第一个字符开始解析,遇到无法解析的则忽略,'14'中的1在二进制中可以解析,而4则无法解析,因)此parseInt('14',2) 相当于parseInt('1', 2),计算出结果是1

平生欢 2022-05-04 13:57:52

map接收一个函数,函数第一个参数为当前遍历的值,第二个参数为index,然后parseInt函数,第一个参数为要解析的值,第二个参数为进制,根据这个进制返回对应的十进制整数。所以题目的返回值可以简化为

parseInt('1',0); //1 radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1
parseInt('2',1); //NAN 第二个参数为2-36的整数,所以返回NaN
parseInt('3',2);// NAN 2进制,只有1和0

百变从容 2022-05-04 13:57:51
string必需。要被解析的字符串。
radix

苹果你个爱泡泡 2022-05-04 13:57:48

我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?

第二个参数是处于2~36没错,但是第二个参数代表解析的进制数,在四进制里面是不可能会出现5这个数字的,所以返回的就是NaN,要想转成5的话应该是parseInt('11', 4)结果就是5

潇烟暮雨 2022-05-04 13:56:36

ratio 值为 (2, 8)的时候,parseInt的第一个参数必须小于ratio

℡寂寞咖啡 2022-05-04 13:48:32

我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?

4进制最大数是3,5大于3,所以NaN。

似最初 2022-05-04 13:37:03

parseInt(string, radix),radix在 (2, 8)的时候,Number(string) < radix。

秋意浓 2022-05-04 08:10:49

parseInt(string, radix)
这道题的关键点在于parseInt的返回值类型,MDN中说返回值类型为10进制,具体是把string所对应的值当做radix对应的进制看待,然后转换成相应的10进制值。
所以在parseInt('3', 2) 中,'3'在2进制中是一个非法的值,2进制中只能存在0和1,所以最后返回了NAN

指尖上得阳光 2022-05-03 19:47:52

这是今天在 Advanced-Frontend组织 看到一个比较有意思的题目。
主要是讲JS的映射与解析
早在 2013年, 加里·伯恩哈德就在微博上发布了以下代码段:

['10','10','10','10','10'].map(parseInt);
// [10, NaN, 2, 3, 4]

parseInt

parseInt() 函数解析一个字符串参数,并返回一个指定基数的整数 (数学系统的基础)。

const intValue = parseInt(string[, radix]);

string 要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。

radix 一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。默认为10。
返回值 返回一个整数或NaN

parseInt(100); // 100
parseInt(100, 10); // 100
parseInt(100, 2); // 4 -> converts 100 in base 2 to base 10

注意:
radix为 undefined,或者radix为 0 或者没有指定的情况下,JavaScript 作如下处理:

  • 如果字符串 string 以"0x"或者"0X"开头, 则基数是16 (16进制).
  • 如果字符串 string 以"0"开头, 基数是8(八进制)或者10(十进制),那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用10,但是并不是所有的浏览器都遵循这个规定。因此,永远都要明确给出radix参数的值。
  • 如果字符串 string 以其它任何值开头,则基数是10 (十进制)。

更多详见parseInt | MDN

map

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

var new_array = arr.map(function callback(currentValue[,index[, array]]) {
 // Return element for new_array
 }[, thisArg])

可以看到callback回调函数需要三个参数, 我们通常只使用第一个参数 (其他两个参数是可选的)。
currentValue 是callback 数组中正在处理的当前元素。
index可选, 是callback 数组中正在处理的当前元素的索引。
array可选, 是callback map 方法被调用的数组。
另外还有thisArg可选, 执行 callback 函数时使用的this 值。

const arr = [1, 2, 3];
arr.map((num) => num + 1); // [2, 3, 4]

更多详见Array.prototype.map() | MDN

回到真实的事例上

回到我们真实的事例上

['1', '2', '3'].map(parseInt)

对于每个迭代map, parseInt()传递两个参数: 字符串和基数
所以实际执行的的代码是:

['1', '2', '3'].map((item, index) => {
	return parseInt(item, index)
})

即返回的值分别为:

parseInt('1', 0) // 1
parseInt('2', 1) // NaN
parseInt('3', 2) // NaN, 3 不是二进制

所以:

['1', '2', '3'].map(parseInt)
// 1, NaN, NaN

由此,加里·伯恩哈德例子也就很好解释了,这里不再赘述

['10','10','10','10','10'].map(parseInt);
// [10, NaN, 2, 3, 4]

如何在现实世界中做到这一点

如果您实际上想要循环访问字符串数组, 该怎么办? map()然后把它换成数字?使用编号!

['10','10','10','10','10'].map(Number);
// [10, 10, 10, 10, 10]

本文始发于我的博客:['1', '2', '3'].map(parseInt) what & why ?

早茶月光 2022-05-03 17:31:23

我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?

埋情葬爱 2022-05-02 07:57:43

在30-seconds-of-code看到一个这个题的变形,分享一下

let unary = fn => val => fn(val)
let parse = unary(parseInt)
console.log(['1.1', '2', '0.3'].map(parse))
把人绕傻吧 2022-05-01 21:53:20

parseInt 基数是一个介于2和36之间的整数 可能第二点这个说法不太准确

~没有更多了~

关于作者

双马尾

暂无简介

0 文章
0 评论
20 人气
更多

推荐作者

花开柳相依

文章 0 评论 0

zyhello

文章 0 评论 0

故友

文章 0 评论 0

对风讲故事

文章 0 评论 0

Oo萌小芽oO

文章 0 评论 0

梦明

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文