我们来看下面这段代码:
let a = ['1', '2', '3'].map(parseInt);
console.log(a);
这段代码比较简单,但是我却连续踩了好几个坑。
再看分析之前,列几个参考选项吧~
A. [1,2,3]
B. [1,NaN,NaN]
C. ['1','2','3']
D. [NaN,NaN,NaN]
E. 正确答案不在这里
F. 选B
下面将从这道题目唯二的两个因素map
,parseInt
开始剖析这道题目。
Array.prototype.map()
MDN:map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
我们先回顾该方法的基本作用与参数:针对每一个元素都调用的回调函数callback(value,index,array)
以及传入该回调函数的 this
指针。
//准备原材料
function myThisObj(){
this.name = "myobj";
}
let obj = new myThisObj();
let oldArr = [10,20,30,40,50];
//开始实验
let newArr1 = oldArr.map(function(value,index,array){
console.log(value,index,array,this);
},obj);
console.log("----------------");
let newArr2 = oldArr.map(function(value,index,array){
console.log(value,index,array,this);
});
console.log("----------------");
输出的结果如下:
知道了map方法的基本功能后,回顾面试题,我们可以知道,输出的结果必定是每一个原数组元素调用函数parseInt返回结果新组合而成的Array(3)
。那么问题便接踵而来了…
- 原题中,并没有给parseInt回调函数显示传入参数,是否意味着调用了parseInt()?
- 假如不传参调用了parseInt(),那么返回什么?
- 假如传参调用了parseInt(),那么传的什么参数?返回什么?
let newArr3 = oldArr.map(function(){
console.log(...arguments);
});
答案是会,不管我们定义的是什么,map的回调函数都会传入那几个参数(当前值,当前下标,数组)。
所以实际上调用的是三次parseInt
:并且每一次都是传入(值,下标,数组),得到的新数组等同于下面:
for(let i=0;i<oldArr.length;i++){
newArr[i] = parseInt(oldArr[i],i,oldArr);
}
剩下的问题即是分析parseInt的方法:
parseInt
MDN:
parseInt(string, radix)
解析一个字符串并返回指定基数的十进制整数, radix 是2-36之间的整数,表示被解析字符串的基数。
由于函数定义中只传入了两个参数,所以我们实际传入的第三个参数Array作废。我们考虑本题最终数组的三个值:
//第一个参数是值,第二个是下标
parseInt('1',0);
parseInt('2',1);
parseInt('3',2);
MDN文档中没有提及的是,如果传入的radix为0,1,那么结果如何?
- 如果radix传入的是0或者空,那么parseInt默认按照十进制处理。(这里的1转成十进制的1)
- 如果radix传入的是1,由于没有1进制,所以会返回NaN。 (不存在一进制== NaN)
- 如果解析的字符串中无法解析成对应进制的number,同样会返回NaN。(这里的3无法转成二进制==NaN)
故答案为 B [1,NaN,NaN]
不传参的情况也顺带一提:
console.log(parseInt())//NaN