Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
YuYuBei opened this issue Jan 22, 2019 · 115 comments
Open

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

YuYuBei opened this issue Jan 22, 2019 · 115 comments
Labels

Comments

@YuYuBei
Copy link

YuYuBei commented Jan 22, 2019

第一眼看到这个题目的时候,脑海跳出的答案是 [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
@yygmind yygmind changed the title ['1', '2', '3'].map(parseInt) 解析 第二题:['1', '2', '3'].map(parseInt) 解析 Feb 12, 2019
@mengfei-nie
Copy link

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

@atheist1
Copy link

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

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

@xingorg1
Copy link

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

@sisterAn
Copy link
Collaborator

这是今天在 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 ?

@jialinhome
Copy link

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

@ravencrown
Copy link

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

@lmislm
Copy link

lmislm commented Feb 18, 2019

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

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

@ravencrown
Copy link

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

@Jer-X
Copy link

Jer-X commented Feb 19, 2019

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

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

@yinyangshibolange
Copy link

yinyangshibolange commented Feb 19, 2019

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

copyed from W3School

@yishuihan-001
Copy link

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

@formattedzzz
Copy link

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

@hxxiaolong
Copy link

我这里有个小视频
https://www.cnblogs.com/54td/p/10429549.html

@Quesle
Copy link

Quesle commented Feb 28, 2019

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

@Shroudfzj
Copy link

Shroudfzj commented Feb 28, 2019

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

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

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

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

@ghost
Copy link

ghost commented Feb 28, 2019

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

@developement711
Copy link

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

@formattedzzz
Copy link

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

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

@lmislm
Copy link

lmislm commented Feb 28, 2019

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。

@developement711
Copy link

明白了,谢谢

@thinkfish
Copy link

我开始也这么理解:第二个参数需要的范围是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

@qiuziz
Copy link

qiuziz commented Mar 7, 2019

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

> ['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

@thinkfish
Copy link

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

> ['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

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

@qiuziz
Copy link

qiuziz commented Mar 8, 2019

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

@thinkfish
Copy link

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

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

@JasonXiang2014
Copy link

在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)
}))
花里胡哨的。

@jefferyE
Copy link

jefferyE commented Mar 12, 2019

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

@lovyliu
Copy link

lovyliu commented Apr 26, 2020

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

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

@lovyliu
Copy link

lovyliu commented Apr 26, 2020

这题的考察点有三个:

  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

@soraly
Copy link

soraly commented May 28, 2020

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

@RoeyXie
Copy link

RoeyXie commented Aug 2, 2020

💛 ['1', '2', '3'].map(parseInt) what & why ? [1,NaN,NaN]
map里面的callBack函数(item,index,arr)=>{ return ...},所以 ['1', '2', '3'].map(parseInt)相当于执行:
parseInt('1',0);parseInt('2',1);parseInt('3',2);

parseInt(string, radix):将一个字符串 string 转换为 radix 进制的整数, radix 为介于2-36之间的数。
参数
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。如果 radix 是 undefined、0或未指定的,JavaScript会假定以下情况:

  1. 如果输入的 string以 "0x"或 "0x"(一个0,后面是小写或大写的X)开头,那么 radix被假定为16,字符串的其余部分被解析为十六进制数。
  2. 如果输入的 string以 "0"(0)开头,radix被假定为 10 (十进制),但不是所有的浏览器都支持。因此,在使用 parseInt时,一定要指定一个 radix。
  3. 如果输入的 string 以任何其他值开头, radix 是 10 (十进制)。

radix 可选
从 2 到 36,代表该进位系统的数字。例如说指定 10 就等于指定十进位。请注意,通常预设值不是 10 进位!
返回值
从给定的字符串中解析出的一个整数。
或者 NaN,当

  1. radix 小于 2 或大于 36 ,或
  2. 第一个非空格字符不能转换为数字。

所以:
parseInt('1',0); 十进制,返回1;
parseInt('2',1); radix不属于2-36期间,返回NaN;
parseInt('3',2); 二进制,二进制只有0和1,返回NaN;
得 [1,NaN,NaN]

@z1455634055
Copy link

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

5不是有效的4进制的有效数字

@jiujiu12
Copy link

我不是很明白,parseInt的第二个参数是可选的,为什么在map中使用就会将 itemindex都传给parseInt做参数呢。

@wangdong2333
Copy link

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

你这种情况基地为4,前面为5,肯定是NAN啊。parseInt(10,4) = 4 parseInt(11,4) = 5 。(满4进1)

@decSunshineHe
Copy link

decSunshineHe commented Jan 29, 2021

觉得parseInt对于进制解析,比较好理解的类似parseInt('20',4) 结果是8,但是对于parseInt('21',4),结果是9,也比较好理解,但是!!!!对于parseInt('25',4),结果是2,这个会比较容易错乱,其实这里是因为5不是4进制以内的数字,所以这里等价于parseInt('2',4),所以结果是2,楼上说的满4进1说法,个人觉得并不准确

@alexlili
Copy link

alexlili commented Feb 3, 2021

以为自己真明白了,过去一段时间,再看此题,又模糊了,那,这次真正把它弄明白!
准备只是,进制:
2进制,基数只能为 0,1
3进制,基数为0,1,2
4进制,基数为0,1,2,3
5进制,基数为0,1,2,3,4
...
8进制,基数为0,1,2,3,4,5,6,7
10进制,基数为0,1,2,3,4,5,6,7,8,9
16进制,基数为0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
发现一个规律,基数们都小于 < 进制数
如 2进制数 的基数 0 和1 都小于2对吧!
继续往下看:
parseInt(str, radix)
str:字符串
radix: 几进制呀
当 radix >0 && (radix>36 || radix < 2) 返回NAN
当 radix = 0 或没传即(radix=undefined)返回十进制

 当正常情况下,
 str左起第一个数一旦大于进制数radix,立马返回 NaN
 str左起第一个数一旦小于进制数radix,就去做运算,直到遇到一个大于等于radix,就不加了哈!
 如parseInt('4215213', 5)   //   4*5 + 1 = 21
['1', '2', '3'].map(parseInt) 
让其变形为 
parseInt('1', 0);    // 1
parseInt('2', 1);    // NaN
parseInt('3', 2);   // 由于 2的二进制数是 0 和 1 组成的,所以要返回 NaN
parseInt('1222', 2)   //首位 1<2哎,  则 1
parseInt('213', 3);     // 2* 3 + 1 = 7;  简单的我会算
['10', '10', '10', '10', '10'].map(parseInt)
parseInt('10', 0);    //  10 无意义吧
parseInt('10', 1);    //  NaN   ’10‘ 的首位 1>=1啦!直接NaN
parseInt('10', 2);   //  1*2 + 0 = 2
parseInt('10', 3)   //   1*3 + 0 = 3
parseInt('10', 4);  //   1*4 + 0 = 4  

进制换算不会自行查阅~

parseInt('4215213', 5) // 4 * 5^2+2 * 5^1+1 * 5^0 = 111 应该是这样的吧

好棒

@Choicelin
Copy link

很容易忽略 map 的第二个参数要传到 parseInt 的进制参数里,造成错误,这题有点意思!

@Code-Pang
Copy link

这题的考察点有三个:

  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)

参数 描述
细绳 必需。要被解析的字符串。
基数 可选。表示要解析的数字的基数。该值介于 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]

map 返回三个参数,parseInt 就自动接收前两个参数的原因就是因为实参的原因吗?有相关的文章可以参考吗?

@zsjun
Copy link

zsjun commented Mar 8, 2021

@xingorg1 不是这样的,

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

不是这样的,parseInt(5,4),会变成parseInt("5",4),但是如果4进制的话,字符串每个位置上的最大值肯定是小于等于4的

@zsjun
Copy link

zsjun commented Mar 8, 2021

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

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

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

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

我觉得还是传使用是最好的

@hello-world-hjf
Copy link

因为

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map#example_using_map_generically
大家可以去看一下这个文档,Array.prototype.map(),里面就有这个例子,解释的很清楚。

@shifengdiy
Copy link

['1', '2', '3'].map(parseInt)
map的参数是一个构造函数 function(item, index) {} 所以parseInt被当做构造函数,以上代码可以看做

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

index被当做了进制

@lazyhero
Copy link

lazyhero commented Aug 16, 2021

我不是很明白,parseInt的第二个参数是可选的,为什么在map中使用就会将 itemindex都传给parseInt做参数呢。

因为map的 callback 函数会被自动传入三个参数:数组元素,元素索引,原数组本身。

题目中

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

结合map源码

/*Array.prototype.map implementation*/
Array.prototype.map = function (callback/*, thisArg*/) {
    var T, A, k;
    if (this == null) {
        throw new TypeError('this is null or not defined');
    }
    // 原数组
    var O = Object(this);
    var len = O.length >>> 0;
    if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function');
    }
    if (arguments.length > 1) { 
        T = arguments[1];
    }
    A = new Array(len);
    k = 0;
    while (k < len) {
        var kValue, mappedValue;
        // k是元素索引
        if (k in O) {
            // 数组元素
            kValue = O[k];
            // 注意这里kValue = ["1", "2", "3"][0], 当前数组元素传入了、索引也传入了、原数组也传入了
            mappedValue = callback.call(T, kValue, k, O); 
            A[k] = mappedValue;
        }
        k++;
    }
    return A;
};

但因为parseInt只接收2个,所以O就被扔了

考点

  • map实现,可以试着看如何修改源码可以让实现符合我们的直觉预期
  • .map api考察 (基础考察,经常用,考没毛病)
  • parseInt api考察(……谁没事用第二个参数?用的时候翻翻文档)

@yhls7
Copy link

yhls7 commented Sep 9, 2021

类似的还有String.prototype.substring.call(undefined),实在是搞不清楚这类题有啥考察的必要,这类题只要翻规范就能知道答案。难道是考察对规范的熟悉程度么,但是仅仅道题也体现不出对规范的熟悉程度吧,就算要考察对规范的熟悉程度那也不应该考察有啥特殊标识符,有啥新功能,介绍一下XX机制之类的么,随便找个实现细节就用来做面试题真有种为了卷而卷的感觉

@ktech0
Copy link

ktech0 commented Apr 19, 2022

没人觉得这个map()很不合理吗?为什么要热心地再给个index参数呢,多余还埋雷。

@GuoguoDad
Copy link

第二点解释不妥当,当parseInt 第二个参数radix 小于 2 或大于 36时,parseInt直接返回 NaN

@Yuweiai
Copy link

Yuweiai commented May 25, 2022

答案:[1, NaN, NaN]

  • var new_array = arr.map(function callback(currentValue[, index[, array]]) {
     // Return element for new_array 
    }[, thisArg])
  • parseInt(string, radix)
  • parseInt('1', 0)

    如果 radixundefined0 或未指定的,JavaScript 会假定以下情况:

    • 如果输入的 string以 "0x"或 "0X"(一个0,后面是小写或大写的X)开头,那么radix被假定为16,字符串的其余部分被当做十六进制数去解析
    • 如果输入的 string以 "0"(0)开头, radix被假定为8(八进制)或10(十进制)。具体选择哪一个radix取决于实现。ECMAScript 5 澄清了应该使用 10 (十进制),但不是所有的浏览器都支持。因此,在使用 parseInt 时,一定要指定一个 radix
    • 如果输入的 string 以任何其他值开头, radix10 (十进制)
  • parseInt('2', 1)

    • radix 不为 undefined0 或未指定的,且小于 2 或大于 36,返回 NaN
  • parseInt('3', 2)

    • 如果 string 不是指定 radix 中的数字,parseInt 将忽略将字符以及所有后续字符,并返回到该点为止已解析的整数值(允许前导和尾随空格)
    • 如果 string 第一个非空字符就不能转换为指定 radix 中的数字,返回 NaN

@Bee-XG
Copy link

Bee-XG commented Jun 23, 2022

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

parseInt(5,4) 是因为规定的是按四进制解析 但是5 明显已经超出了 四进制的最大值 所以被解析为 了 NaN

@Yangfan2016
Copy link

好经典的题 360 考过
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt

parseInt(x,y);
// x 为 string
// y 为进制   取值范围 2-36  默认十进制 


@yinzuowen
Copy link

第一眼看到这个题目的时候,脑海跳出的答案是 [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

基数的范围是2-36,不在此范围内,parseInt直接返回NaN

@xiaogu-123
Copy link

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

===> 看了老哥的解析瞬间明白了,思路清晰
parseInt("45",5) 当解析45时,4属于范围内,所以得到4,但是5不属于,所以走到这里直接把后面抛弃掉,相当于parseInt("4",5); ---最终得到4。

parseInt("454",5) 当解析454时,4属于范围内,所以得到4,但是5不属于,所以走到这里直接把后面全部抛弃掉, 相当于parseInt("4",5); ---最终得到4。 

parseInt("44",5) 当解析44时,4属于范围内,后面那个4还是在范围内,所以,算作一个整体,属于正常,不进行任何操作   根据进制算法,最终算出,从右往左 45^0+45^1 = 24

parseInt("445",5) 当解析445时,4属于范围内,后面那个4还是在范围内, 但是在后面的5不属于, 所以,5抛弃掉,只取44,相当于 parseInt("44",5); , 根据进制算法,最终算出,从右往左 45^0+45^1 = 24

parseInt("544",5) 当解析544时,5直接不属于范围内,所以全部抛弃掉,只取"", 相当于parseInt("",5); 返回NaN

parseInt("5",5) 当解析5时,5直接不属于范围内,所以全部抛弃掉,只取"", 相当于parseInt("",5); 返回NaN

@Bibooo25730
Copy link

脑壳疼

@xiaogu-123
Copy link

xiaogu-123 commented May 30, 2023 via email

@ChengYu08
Copy link

将字符串解析指定为 指定进制 字符串中的值应该小于 进制的值 不然返回NaN
如果不传 (或者为0) 默认是10进制。小数转10进制 默认向下取整
parseInt("字符串",进制) 意思是将字符串看成 ?进制 解析 然后返回10进制的数

parseInt('100', 2); 000 001 010 011 100 ==>4

parseInt("17",8); 00 01 02 03 04 05 06 07 10 11 12 13 14 15 16 17 ==>15

parseInt("11",2); 00 01 10 11 =》 3

@xiaogu-123
Copy link

xiaogu-123 commented Nov 16, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests