面试题
请你说出以下代码的执行结果:
['1', '2', '3'].map(parseInt);
如果大家第一次做这道题,几乎都会认为答案是 [1,2,3]
, 原因很简单:paseInt
会把一个字符串转化为整数。 ‘1’, ‘2’, ‘3’ 转化为整数分别是 1 , 2 , 3,所以以上代码会循环执行 3
次,分别返回 1 , 2 , 3。
知识回顾
map函数
在大多数场景下,我们使用 map 函数只会使用到它的第一个参数,也就是当前遍历的元素。比如以下代码,第一次 item 是 '1'
,第二次 item 是 '2'
…
我们忽略了 map
函数的第二个参数和第三个参数。map 函数的第二个参数是当前遍历元素的下标(或者说索引)。map 函数的第三个参数是数组本身。
const result = ["1", "2", "3"].map((item, index, arr) => {
console.log(arr); // ['1', '2', '3']
console.log(index); // 当前索引
console.log(item); //当前遍历的元素
return item * 2;
});
parseInt函数
parseInt() 函数可解析一个字符串,并返回一个整数。
语法格式:parseInt(string, radix)
其中,radix
用于描述你当前传入的字符串是 几进制。
如果你没有传第二个参数 radix
,那么根据以下规则来自动判断 string
是几进制。
- 如果字符串string以"0x"或者"0X"开头, 则基数是16 (16进制)
- 如果字符串string以"0"开头, 基数是8(八进制)或者10(十进制),那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用10,但是并不是所有的浏览器都遵循这个规定。因此,永远都要明确给出radix参数的值。
- 如果字符串string以其它任何值开头,则基数是10 (十进制)。
如果你传第二个参数 radix
,radix
的范围需要在2 ~ 36之内
。如果在2 ~ 36之外
会返回NaN。
我们看以下几个例子:
//例1
console.log(parseInt(5, 8));
// 例2
console.log(parseInt(5, 2));
// 例3
console.log(parseInt(5, 0));
// 例4
console.log(parseInt(5, 1));
// 例5
console.log(parseInt(123, 5));
例子1:console.log(parseInt(5, 8));
结果为:5
解释:将字符串"5"解析为十进制数,因为第二个参数为8,表示使用八进制解析。但是"5"并不是八进制数字,所以解析结果为十进制数5。
例子2:console.log(parseInt(5, 2));
结果为:NaN
解释:将字符串"5"解析为二进制数,因为第二个参数为2,表示使用二进制解析。但是"5"并不是有效的二进制数字,所以解析结果为NaN(Not
a Number)。
例子3:console.log(parseInt(5, 0));
结果为:5
解释:第二个参数为0时,parseInt函数会根据字符串的前缀来判断要使用的进制。由于"5"没有前缀,所以默认按照十进制解析,结果为十进制数5。
例子4:console.log(parseInt(5, 1));
结果为:NaN
解释:第二个参数为1,表示使用基数为1进行解析。在数学中,基数必须大于1,因此无法解析为有效的数字,结果为NaN。
例子5:console.log(parseInt(123, 5));
结果为:38
解释:将字符串"123"解析为五进制数,因为第二个参数为5,表示使用五进制解析。将字符串中的每个字符按照五进制转换为数字,得到15^2 +
25^1 + 3*5^0 = 38。因此解析结果为38。
题目分析
理解了 map 和 parseInt 之后,我们再来看 ['1', '2', '3'].map(parseInt);
。
第一次循环:
parseInt('1', 0);
// 参数:'1',进制值为默认的十进制(0)
// 返回结果:1
第二次循环:
parseInt('2', 1);
// 参数:'2',进制值为 1
// 返回结果:NaN(无效的一进制数字)
第三次循环:
parseInt('3', 2);
// 参数:'3',进制值为 2
// 返回结果:NaN(无效的二进制数字)
因此,返回的结果是[1, NaN, NaN]
。
变种题:
console.log(parseInt(1/0, 19)) // 18
console.log(parseInt(false, 16)) // 250
console.log(parseInt(parseInt, 16)) // 15
console.log(parseInt({}, 16)) // NaN
console.log(parseInt(1/0, 19))
解析:parseInt里面有两个参数,第二个参数是19,十九进制包括(0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i);然后分析第一个参数1/0,它的运算结果是 Infinity
,那么相当于要把 Infinity
从19进制转化为十进制,我们从第一个字符I开始 – 19进制有i,表示18,接下来字母n ,19进制里面没有 n,既然不认识,那就不管了,立即返回i(对应十进制中的18),所以返回结果为18。
console.log(parseInt(false, 16))
解析:parseInt里面有两个参数,第二个参数16,十六进制包括(0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f);然后分析第一个参数false,转化为字符串(parseInt第一个参数非字符串先转化为字符串)==> false。,从第一个字符开始分析,f ,a,接下来是 l
,16进制里面没有 l
。立即返回fa (十六进制的fa转换成十进制等于250),结果为250
console.log(parseInt(parseInt, 16))
解析:parseInt里面有两个参数,第二个参数是16,十六进制包括(0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f);然后分析第一个参数 parseInt,转化为字符串,我们看看String(parseInt)结果是什么, function parseInt() { [native code] }, 好的,从第一个字符开始分析,f认识,u不认识,立即返回f (十六进制的f转换成十进制等于15), 返回结果15
console.log(parseInt({}, 16))
解析:parseInt里面有两个参数,第二个参数是16,十六进制包括(0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f);然后分析第一个参数{}, 我们看看String({})是个啥,[object Object], 第一个字符是[, 不认识,那就返回NaN吧
参考:https://juejin.cn/post/7049161354703273998