第 2 题:['1', '2', '3'].map(parseInt) what & why ?
第一眼看到这个题目的时候,脑海跳出的答案是 [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)
接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。
了解这两个函数后,我们可以模拟一下运行情况
- parseInt('1', 0) // radix 为 0 时,且 string 参数不以 0x 和 0 开头时,按照 10 为基数处理。这个时候返回 1
- parseInt('2', 1) // 基数为 1(1 进制)表示的数中,最大值小于 2,所以无法解析,返回 NaN
- 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(41)
['1', '2', '3'].map(parseInt)等价于[parseInt('1',0), parseInt('2',1), parseInt('3',2)]
总之 radix在[2-9]区间内 Number(string.charAt(0)) 不能大于等于 radix
0x和0X开头的默认都是 16进制字符串转10进制 如果指定了radix 那么都是按常规字符串处理=>0
我这里有个小视频
https://www.cnblogs.com/54td/p/10429549.html
基数为1(1进制)的时候,返回的结果都是NaN,所以parseInt('2', 1)返回结果是NaN
基数为2(2进制)的时候,字符串的值要求是0和1,所以parseInt('3', 2)返回结果是NaN
根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:
当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措
其实这个可以用函数式思维来解决,具体可以看月影老师写的这篇博文
parseInt('11', "4") 这个为啥等于5呢,他4进制,11应该也不在其范围内么,怎么会得出的结果为5呢
'11'表示的是4进制的数啊 5 是十进制 1=>1 2=>2 3=>3 10=>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。
明白了,谢谢
一般对我来说,在平时coding时,都是箭头函数,这点能避免很多问题的,另外 parseInt在使用时,我一般都是会加上第二个参数为10
这么多答案,而且那些答案也说得有理有据,分析得非常深入
但是,还是觉得你的最正确
@thinkfish 哈哈 实际应用肯定是最小减少问题,但原理了解透彻还是很有必要的嘛
在理,至少在遇到问题的时候能快速定位
这种方法绕过了parseInt的第二个参数,实际执行如下:
console.log(['1.1', '2', '0.3'].map( item => {
return parseInt(item)
}))
花里胡哨的。
@developement711
parseInt的第二个参数:radix参数为n 将会把第一个参数看作是一个数的n进制表示,而返回的值则是十进制
例如: parseInt('11', 4) // 将'11'看作4进制数,返回十进制数5 => 1*4^1 + 1*4^0 = 5
首先看看 parseInt 方法在 MDN 的文档
接下来分析 map 中的每一次迭代调用 parseInt 的参数:
parseInt('1', 0, ['1', '2', '3'])
输出1
parseInt('2', 1, ['1', '2', '3'])
输出NaN
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))
这个的答案能否解释一下呢?
我是这样理解的:
unary
函数接收一个回调函数fn
,返回一个闭包。也就是说
parse
函数等同于let parse = val => parseInt(val)
传入
parse
函数的参数依次是(箭头函数没有arguments
所以超过形参的实参会被忽略):parse('1.1')
返回1
parse('2')
返回2
parse('0.3')
返回0
输出
[1, 2, 0]
谢谢回答~
做完每一题(学习技术一定要以一手资料为主):
题目2答案:分别分析了specification里面是如何描述 parseInt 和 Array.prototype.map 的。
这题的考察点有三个:
Array.map方法的callback函数接收三个参数,(value, index, array)。
而parseInt方法接收两个参数。这里就涉及到函数参数个数问题了,在JS中,不看形参的,看实参,就是你传多少个参数给我无所谓,我函数内部只用我需要的,其内部使用arguments进行引用,具体机制可以查阅相关资料文章。
比如这里的parseInt方法,虽然map的callback给它传了三个参数,但是它只会用到前两个参数,也就是map函数callback的value和index。
所以题目就转化成了如下形式:
而接下来,你就要知道parseInt方法的参数意义了:
看了这个题目后专门去研究了parseInt,parseInt的参数
parseInt(String,radix)里的radix根本就没有这么简单,radix根本就不是单纯的进制,详情看我简书的文章
parseInt详解-你以为radix指的进制吗?
大哥。。。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就明白了
parseInt('45', 5) //4 这个应该算是parseInt的内部处理,跟radix是不是进制数没有关系。
MDN文档上是这样写的:
如果 parseInt 遇到的字符不是指定 radix 参数中的数字,它将忽略该字符以及所有后续字符,并返回到该点为止已解析的整数值。 parseInt 将数字截断为整数值。 允许前导和尾随空格。
parseInt('14', 2) parseInt从参数的第一个字符开始解析,遇到无法解析的则忽略,'14'中的1在二进制中可以解析,而4则无法解析,因)此parseInt('14',2) 相当于parseInt('1', 2),计算出结果是1
map接收一个函数,函数第一个参数为当前遍历的值,第二个参数为index,然后parseInt函数,第一个参数为要解析的值,第二个参数为进制,根据这个进制返回对应的十进制整数。所以题目的返回值可以简化为
第二个参数是处于2~36没错,但是第二个参数代表解析的进制数,在四进制里面是不可能会出现5这个数字的,所以返回的就是NaN,要想转成5的话应该是parseInt('11', 4)结果就是5
ratio 值为 (2, 8)的时候,parseInt的第一个参数必须小于ratio
4进制最大数是3,5大于3,所以NaN。
parseInt(string, radix),radix在 (2, 8)的时候,Number(string) < radix。
parseInt(string, radix)
这道题的关键点在于parseInt的返回值类型,MDN中说返回值类型为10进制,具体是把string所对应的值当做radix对应的进制看待,然后转换成相应的10进制值。
所以在parseInt('3', 2) 中,'3'在2进制中是一个非法的值,2进制中只能存在0和1,所以最后返回了NAN
这是今天在 Advanced-Frontend组织 看到一个比较有意思的题目。
主要是讲JS的映射与解析
早在 2013年, 加里·伯恩哈德就在微博上发布了以下代码段:
parseInt
parseInt()
函数解析一个字符串参数,并返回一个指定基数的整数 (数学系统的基础)。string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。默认为10。返回值
返回一个整数或NaN注意:
在
radix
为 undefined,或者radix
为 0 或者没有指定的情况下,JavaScript 作如下处理:更多详见parseInt | MDN
map
map()
方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。可以看到
callback
回调函数需要三个参数, 我们通常只使用第一个参数 (其他两个参数是可选的)。currentValue
是callback 数组中正在处理的当前元素。index
可选, 是callback 数组中正在处理的当前元素的索引。array
可选, 是callback map 方法被调用的数组。另外还有
thisArg
可选, 执行 callback 函数时使用的this 值。更多详见Array.prototype.map() | MDN
回到真实的事例上
回到我们真实的事例上
对于每个迭代
map
,parseInt()
传递两个参数: 字符串和基数。所以实际执行的的代码是:
即返回的值分别为:
所以:
由此,加里·伯恩哈德例子也就很好解释了,这里不再赘述
如何在现实世界中做到这一点
如果您实际上想要循环访问字符串数组, 该怎么办?
map()
然后把它换成数字?使用编号!本文始发于我的博客:['1', '2', '3'].map(parseInt) what & why ?
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
在30-seconds-of-code看到一个这个题的变形,分享一下
parseInt 基数是一个介于2和36之间的整数 可能第二点这个说法不太准确