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 · 81 comments
Open

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

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

Comments

@YuYuBei
Copy link

@YuYuBei 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

This comment has been minimized.

Copy link

@mengfei-nie mengfei-nie commented Feb 13, 2019

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

@atheist1

This comment has been minimized.

Copy link

@atheist1 atheist1 commented Feb 14, 2019

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

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

This comment has been minimized.

Copy link

@xingorg1 xingorg1 commented Feb 15, 2019

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

@sisterAn

This comment has been minimized.

Copy link

@sisterAn sisterAn commented Feb 16, 2019

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

This comment has been minimized.

Copy link

@jialinhome jialinhome commented Feb 18, 2019

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

@ravencrown

This comment has been minimized.

Copy link

@ravencrown ravencrown commented Feb 18, 2019

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

@lmislm

This comment has been minimized.

Copy link

@lmislm lmislm commented Feb 18, 2019

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

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

@ravencrown

This comment has been minimized.

Copy link

@ravencrown ravencrown commented Feb 18, 2019

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

@Jer-X

This comment has been minimized.

Copy link

@Jer-X 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

This comment has been minimized.

Copy link

@yinyangshibolange yinyangshibolange commented Feb 19, 2019

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

copyed from W3School

@yishuihan-001

This comment has been minimized.

Copy link

@yishuihan-001 yishuihan-001 commented Feb 19, 2019

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

@formattedzzz

This comment has been minimized.

Copy link

@formattedzzz formattedzzz commented Feb 19, 2019

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

@hxxiaolong

This comment has been minimized.

Copy link

@hxxiaolong hxxiaolong commented Feb 25, 2019

@Quesle

This comment has been minimized.

Copy link

@Quesle Quesle commented Feb 28, 2019

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

@Shroudfzj

This comment has been minimized.

Copy link

@Shroudfzj 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

This comment has been minimized.

Copy link

@ghost ghost commented Feb 28, 2019

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

@developement711

This comment has been minimized.

Copy link

@developement711 developement711 commented Feb 28, 2019

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

@formattedzzz

This comment has been minimized.

Copy link

@formattedzzz formattedzzz commented Feb 28, 2019

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

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

@lmislm

This comment has been minimized.

Copy link

@lmislm 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

This comment has been minimized.

Copy link

@developement711 developement711 commented Feb 28, 2019

明白了,谢谢

@thinkfish

This comment has been minimized.

Copy link

@thinkfish thinkfish commented Mar 4, 2019

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

This comment has been minimized.

Copy link

@qiuziz 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

This comment has been minimized.

Copy link

@thinkfish thinkfish 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

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

@qiuziz

This comment has been minimized.

Copy link

@qiuziz qiuziz commented Mar 8, 2019

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

@thinkfish

This comment has been minimized.

Copy link

@thinkfish thinkfish commented Mar 9, 2019

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

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

@JasonXiang2014

This comment has been minimized.

Copy link

@JasonXiang2014 JasonXiang2014 commented Mar 10, 2019

在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

This comment has been minimized.

Copy link

@jefferyE jefferyE commented Mar 12, 2019

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

@prefertwo

This comment has been minimized.

Copy link

@prefertwo prefertwo commented Jul 17, 2019

一、what 正确答案

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

image

二、why

(一)理解map

1、map概念

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
"map"即"映射",也就是原数组被"映射"成对应新数组。
新建一个数组,需要有承载对象,也意味着原始数组在调用它后不会发生变化;
该数组中的每个元素都调用一个提供的函数后返回结果。

var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1); //输 出: Array [2, 8, 18, 32]

2、用JavaScript实现map

if (!Array.prototype.map) {
  Array.prototype.map = function(callback, thisArg) {

    var T, A, k;

    if (this == null) {
      throw new TypeError(" this is null or not defined");
    }

    // 1. 将O赋值为调用map方法的数组.
    var O = Object(this);

    // 2.将len赋值为数组O的长度.
    var len = O.length >>> 0;

    // 3.如果callback不是函数,则抛出TypeError异常.
    if (Object.prototype.toString.call(callback) != "[object Function]") {
      throw new TypeError(callback + " is not a function");
    }

    // 4. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined.
    if (thisArg) {
      T = thisArg;
    }

    // 5. 创建新数组A,长度为原数组O长度len
    A = new Array(len);

    // 6. 将k赋值为0
    k = 0;

    // 7. 当 k < len 时,执行循环.
    while(k < len) {

      var kValue, mappedValue;

      //遍历O,k为原数组索引
      if (k in O) {

        //kValue为索引k对应的值.
        kValue = O[ k ];

        // 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
        mappedValue = callback.call(T, kValue, k, O);

        // 返回值添加到新数组A中.
        A[ k ] = mappedValue;
      }
      // k自增1
      k++;
    }

    // 8. 返回新数组A
    return A;
  };      
}

(二)理解parseInt

1、parseInt 概念

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

parseInt(string, radix);

  • string 表示
    要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。
  • radix表示
    一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数"10"表示使用我们通常使用的十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常将值默认为10。

2、 返回值

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

parseInt("Hello", 8); // 输出NaN, 因为根本就不是数值
parseInt("546", 2);   // 输出NaN,因为除了“0、1”外,其它数字都不是有效二进制数字

参考文章

parseInt("Hello", 8); // 输出NaN, 因为根本就不是数值

parseInt("Hello", 8); // 输出NaN
这个输出NaN 的根本原因不是因为它不是数值,而是因为 后面的基数限制了。将字母按照 a=10, 这样依次排列之后,只要你的后面基数大于 字母对应的 数值,就能转换成数字。
比如:console.log( parseInt('hello', 36) ) // 29234652

@prefertwo

This comment has been minimized.

Copy link

@prefertwo prefertwo commented Jul 17, 2019

console.log( parseInt(0xaa, 20) ) // 540
这个输出会先把 0xaa 按照十六进制转换为十进制数 170,然后再将 170 按照 20进制 转换 得到 540

console.log( parseInt('aaa', 20) ) // 4210
这个输出会 直接将 aaa 作为20进制解析,a=10, 10 * 20^0 + 10 * 20^1 + 10*20^2 = 4210

console.log( parseInt('ka', 20) ) // NaN
这个会 直接将 ka 作为20进制解析, 但因为要解析的字符串单个值必须小于 基数(20)而 k=20, 所以返回 NaN
所以 parseInt("Hello", 8); // 输出NaN,并不是因为hello不是数值(自己理解的)。

@IAMSBLOL

This comment has been minimized.

Copy link

@IAMSBLOL IAMSBLOL commented Jul 18, 2019

parseInt接受两个参数~1,0为十进制,2,1不存在,3,2不存在。
因此,1,nan,nan

@fyuxiang

This comment has been minimized.

Copy link

@fyuxiang fyuxiang commented Jul 18, 2019

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

parseInt第二参数表示的是第一个参数的进制表示,所以第一个参数不能越过这个进制的表示方法,比如二进制,那么单个字符最大不能超过2

@Arthas625022055

This comment has been minimized.

Copy link

@Arthas625022055 Arthas625022055 commented Jul 24, 2019

最高赞的说法有点问题哈,第二点和第三点可能对进制理解的有误
2进制里面是没有2的,只有1、0,最小进制为2进制。
所以

parseInt('2', 1) //基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN
parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
关于第二点,第二个参数需要的范围是2~36之间,所以parseInt('0', 1),也会返回NaN。
第三点,parseInt('3', 2)最大值是小于2的。parseInt('2', 2),返回的依旧是NaN。

@juzhiqiang

This comment has been minimized.

Copy link

@juzhiqiang juzhiqiang commented Jul 31, 2019

image
按mdn解释第二参数的有效参在2-36之间
大于36的自然不用多解释在因为----字母表中的字母来表示大于 9 的数字。26个字母加数字能表达的最大值就是36 所以大于这个进制的因为无法表示一律NAN ;
而小于2的本页应该类似大于36的 但文档种 明确指出0或没有指定情况下按下列规则,则这个时候0就是10进制
image

通过上面得出 数组种3个数的索引是0 ,1,2 ,对于的值是1,2,3,
根据文档
1的10进制依然为1 ,
2的1进制不符合 规范直接返回NAN ,
二进制规则有一条逢二进一,是不可能出现大于1的数,所以不符合规范 也直接返回NAN

@yangzaiwangzi

This comment has been minimized.

Copy link

@yangzaiwangzi yangzaiwangzi commented Aug 6, 2019

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

为啥parseInt("10",3) =>//3 ???

@ylfeng250

This comment has been minimized.

Copy link

@ylfeng250 ylfeng250 commented Aug 6, 2019

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

为啥parseInt("10",3) =>//3 ???

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

@AnthonyYY

This comment has been minimized.

Copy link

@AnthonyYY AnthonyYY commented Aug 7, 2019

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

parseInt(3, 4) 就不会报错,4代表四进制, 四进制的话则需要parseInt的数就不会是大于数字3的数,因为逢4进1掉了, 大于3的数不合法.

@pudi2018

This comment has been minimized.

Copy link

@pudi2018 pudi2018 commented Aug 16, 2019

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

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

能否给解释下

@iamhmx

This comment has been minimized.

Copy link

@iamhmx iamhmx commented Aug 29, 2019

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

parseInt('5', 4)结果为NaN, 是因为在4进制中不存在5,因为满4就进1了,4进制中的5应该是11

@Cherryones

This comment has been minimized.

Copy link

@Cherryones Cherryones commented Sep 3, 2019

以为自己真明白了,过去一段时间,再看此题,又模糊了,那,这次真正把它弄明白!
准备只是,进制:
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 应该是这样的吧

@xianshannan

This comment has been minimized.

Copy link

@xianshannan xianshannan commented Sep 6, 2019

如果你仔细点,同时也熟悉 parseInt 和 map 的语法,这道题说难也不难,不过要让面试官满意还是得花多点功夫。

或许许多人认为是 [1, 2, 3],但是真正的答案是[1, NaN, NaN]

本人也把这个详细的说明归纳在本人的 github 上面,https://github.com/xianshannan/interview/issues/25

map 的语法

有点 JavaScript 基础的基本都知道 map 的基本用法。

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

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

parseInt 语法

parseInt(string, radix);

parseInt(string, radix) 将一个字符串 string 转换为 radix 进制的整数, radix 为介于 2-36 之间的数。

radix 参数为 n 将会把第一个参数看作是一个数的 n 进制表示,而返回的值则是十进制

如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN第一个字符不为数字或者大于等于进制数,就会返回 NAN

当 radix 为 0 、false、null、undefined,如果 string 不包含 0x,一般默认为十进制。

进制转换规则

假设 n 为进制,1ND 为第一位数,2ND 为第二数(以此类推),result 为结果,二位数的转换规则如下:

result => 1ND * n ^ 1 + 2ND * n ^ 0 = 3

js 语法如下:

1ND * Math.pow(n,1) + 2ND * Math.pow(n,0) 

假设 n 为进制,result 为结果,三位数的转换规则如下:

result => 1ND * n ^ 2 + 2ND * n ^ 1 + 3ND * n ^ 0 = 3

js 语法如下:

1ND * Math.pow(n,2) + 2ND * Math.pow(n,1) + 3ND * Math.pow(n,0) 

假设 n 为进制,result 为结果,四位数的转换规则如下:

result => 1ND * n ^ 3 + 2ND * n ^ 2 + 3ND * n ^ 1 + 4ND * n ^ 0= 3

js 语法如下:

1ND * Math.pow(n,3) + 2ND * Math.pow(n,2) + 3ND * Math.pow(n,1) + 4ND * Math.pow(n,0) 

一些例子运行情况

  • 当 radix 为 0 、false、null、undefined,如果 string 不包含 0x,一般默认为十进制。

    parseInt('1', 0)
    parseInt('1')
    parseInt('1', false)
    parseInt('1', null)

    上面的返回结果都为 1.

  • radix 为介于 2-36之间,基数为 1 无效,所以无法解析,返回 NaN

    parseInt('0', 1)  
    parseInt('2', 1)  

    上面的返回结果都为 NAN.

  • 第一个字符不为数字或者大于等于进制数,就会返回 NAN。

    parseInt('dd', 2) 
    parseInt(null, 2) 
    parseInt('2', 2) 
    parseInt('3', 2) 
    parseInt('4', 4) 
    parseInt('5', 4) 

    上面的返回结果都为 NAN.

参考资料

@pydick

This comment has been minimized.

Copy link

@pydick pydick commented Sep 8, 2019

如果你仔细点,同时也熟悉 parseInt 和 map 的语法,这道题说难也不难,不过要让面试官满意还是得花多点功夫。

或许许多人认为是 [1, 2, 3],但是真正的答案是[1, NaN, NaN]

本人也把这个详细的说明归纳在本人的 github 上面,https://github.com/xianshannan/interview/issues/25。

map 的语法

有点 JavaScript 基础的基本都知道 map 的基本用法。

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

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

parseInt 语法

parseInt(string, radix);

parseInt(string, radix) 将一个字符串 string 转换为 radix 进制的整数, radix 为介于 2-36 之间的数。

radix 参数为 n 将会把第一个参数看作是一个数的 n 进制表示,而返回的值则是十进制

如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN第一个字符不为数字或者大于等于进制数,就会返回 NAN

当 radix 为 0 、false、null、undefined,如果 string 不包含 0x,一般默认为十进制。

进制转换规则

假设 n 为进制,1ND 为第一位数,2ND 为第二数(以此类推),result 为结果,二位数的转换规则如下:

result => 1ND * n ^ 1 + 2ND * n ^ 0 = 3

js 语法如下:

1ND * Math.pow(n,1) + 2ND * Math.pow(n,0) 

假设 n 为进制,result 为结果,三位数的转换规则如下:

result => 1ND * n ^ 2 + 2ND * n ^ 1 + 3ND * n ^ 0 = 3

js 语法如下:

1ND * Math.pow(n,2) + 2ND * Math.pow(n,1) + 3ND * Math.pow(n,0) 

假设 n 为进制,result 为结果,四位数的转换规则如下:

result => 1ND * n ^ 3 + 2ND * n ^ 2 + 3ND * n ^ 1 + 4ND * n ^ 0= 3

js 语法如下:

1ND * Math.pow(n,3) + 2ND * Math.pow(n,2) + 3ND * Math.pow(n,1) + 4ND * Math.pow(n,0) 

一些例子运行情况

当 radix 为 0 、false、null、undefined,如果 string 不包含 0x,一般默认为十进制。

parseInt('1', 0)
parseInt('1')
parseInt('1', false)
parseInt('1', null)

上面的返回结果都为 1.

radix 为介于 2-36之间,的数基数为 1 无效,所以无法解析,返回 NaN

parseInt('0', 1)  
parseInt('2', 1)  

上面的返回结果都为 NAN.

第一个字符不为数字或者大于等于进制数,就会返回 NAN。

parseInt('dd', 2) 
parseInt(null, 2) 
parseInt('2', 2) 
parseInt('3', 2) 
parseInt('4', 4) 
parseInt('5', 4) 

上面的返回结果都为 NAN.

参考资料

map 回调函数放内置函数原理是什么?
eg:
let newArr=['1','2','3'].map((item,index)=>parseInt(item,index));
let newArr=['1','2','3'].map(parseInt);
参数是怎样传递对应

@chineseLiao

This comment has been minimized.

Copy link

@chineseLiao chineseLiao commented Sep 24, 2019

如果面试中遇到这个问题,我应该会这样回答,不知道算不算答对
['1', '2', '3'].map(parseInt)
等价于
['1', '2', '3'].map((item,index)=>{
console.log(parseInt(item,index));
});
考点是不是在parseInt的转换基数,我在控制台输出的结果是一致的;

@liuruchao

This comment has been minimized.

Copy link

@liuruchao liuruchao commented Nov 12, 2019

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

parseInt(5,4) 4进制中没有5这个数值,无法解析,当然返回NaN

@hanqizheng

This comment has been minimized.

Copy link

@hanqizheng hanqizheng commented Nov 20, 2019

我有一个问题

parseInt('14', 2) // 1

返回的结果为什么是 1?

@yygmind yygmind added the JS基础 label Dec 16, 2019
@fyuxiang

This comment has been minimized.

Copy link

@fyuxiang fyuxiang commented Dec 30, 2019

@Smacricket

This comment has been minimized.

Copy link

@Smacricket Smacricket commented Dec 31, 2019

['1','2','3'].map(parseInt)默认是
['1','2','3'].map((item,index)=>parseInt(item,index)); // [1, NaN, NaN]
修改默认不传index就可以了
['1','2','3'].map((item,index)=>parseInt(item));// [1, 2, 3]
(为什么parseInt默认会这样,我也想知道)

@yzy132

This comment has been minimized.

Copy link

@yzy132 yzy132 commented Jan 6, 2020

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

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

这个的答案是什么呢?

@zowiegong

This comment has been minimized.

Copy link

@zowiegong zowiegong commented Jan 6, 2020

首先看看 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]

@yzy132

This comment has been minimized.

Copy link

@yzy132 yzy132 commented Jan 7, 2020

首先看看 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))

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

@zowiegong

This comment has been minimized.

Copy link

@zowiegong zowiegong commented Jan 7, 2020

在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]

@yzy132

This comment has been minimized.

Copy link

@yzy132 yzy132 commented Jan 8, 2020

在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]

谢谢回答~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.