这道很经典的面试题已经过去很多年了,但是现在依然被很多人 传颂 着。以前研究过这道题,觉得弄懂了。但是今天被别人问起这道题时回答的又有点 模棱两可。
我们先看一下输出结果
考察点:
- Array.map()
- parseInt()
- 进制(进制之间转换)
那我们分别研究一下这三个要点。
Array.map()
这个应该是我们最常用的Array
方法之一。早在ES6
就有了。
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
var new_array = arr.map(function callback(currentValue,index,array) {
// Return element for new_array
},thisArg)
-
Array.map()参数
callback
生成新数组元素执行的函数(三个参数)
currentValue
callback 数组中正在处理的当前元素。
index
callback 数组中正在处理的当前元素的索引。
array
map 方法被调用的数组。
thisArg
执行 callback 函数时使用的this 值。
返回值
一个新数组,每个元素都是回调函数的结果。
-
Array.map()示例
let arr = ["1","2","3"].map(function callback(currentValue,index,array) {
console.log(`${currentValue}+${index} [${array}]`)
return currentValue*2
});
console.log(arr);
output:
// 1+0 [1,2,3]
// 2+1 [1,2,3]
// 3+2 [1,2,3]
// [2, 4, 6]
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9]
parseInt()
parseInt(string, radix);
-
parseInt()参数
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串。
radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。当未指定基数时,不同的实现会产生不同的结果,通常认为其值默认为10,但是请在使用时总是显示的指定它。
注意 radix参数为n 将会把第一个参数看作是一个数的n进制表示,而返回的值则是十进制的。
这是MDN上的解释 parseInt(string, radix) 将一个字符串 string 转换为 radix 进制的整数, radix 为介于2-36之间的数。
对于上面两句话我理解的时候总是有点怪。我觉得可以这样理解parseInt(string, radix)
, 把radix
进制的string
转成10
进制的值,并返回
例如:
parseInt('123', 5) // 将'123'看作5进制数,返回十进制数38 => 1*5^2 + 2*5^1 + 3*5^0 = 38
这里将5
进制的123
转成10
进制为38
-
parseInt()示例
parseInt("20"); //返回20 radix默认为10,也就是10进制的20转成10进制,那么也是20
parseInt("10",2);//返回2 radix为2,也就是2进制的10转成10进制,1*2^1+1*2^0 = 2
parseInt("103",2);//返回2 radix为2,也就是2进制的103转成10进制,因为2进制只包括0,1,所以3不是2进制的数字(只计算3之前的值也就是10),1*2^1+1*2^0 = 2
parseInt("213",4);//返回39 radix为4,也就是4进制的213转成10进制,2*4^2+1*4^1+3*4^0 = 32+4+3 = 39
...
这里进制是怎样转换的呢,比如4
进制的213
转成10
进制
2*4^2+1*4^1+3*4^0 = 32+4+3 = 39
拿第一个数*进制的第一个数的位数的次方+第二个数*进制的第二个数的位数的次方+···直到加上最后一位数*进制的0次方(位数从右向左数0,1,2...)
看下面的介绍:
在基数radix为 undefined,或者基数为 0 或者没有指定的情况下,JavaScript 作如下处理:
如果字符串 string 以"0x"或者"0X"开头, 则基数是16 (16进制).
如果字符串 string 以"0"开头, 基数是8(八进制)或者10(十进制),那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用10,但是并不是所有的浏览器都遵循这个规定。因此,永远都要明确给出radix参数的值。
如果字符串 string 以其它任何值开头,则基数是10 (十进制)。
如果第一个字符不能被转换成数字,parseInt返回NaN。
算术上, NaN 不是任何一个进制下的数。 你可以调用isNaN 来判断 parseInt 是否返回 NaN。NaN 参与的数学运算其结果总是 NaN。
那我们来看这几个例子怎么返回
parseInt("1",0); //radix为10也就是10进制的1转10进制,也就是 1
parseInt("2",1);//radix 介于2和36之间的整数,当radix不在这个范围内的解析全都返回 NaN
parseInt("3",2);// 3不是2进制的数字,3前面也没有其他数字,所以这里返回 NaN
我们知道parseInt
为一个函数,其源代码应该是这个样子的:
function parseInt(string, radix){
return xxx;
}
当写成这样Arrar.map(parseInt)
的形式时
callback === parseInt
parseInt(string, radix)
的两个参数分别对应currentValue index
这个时候parseInt
就变成了
function parseInt(currentValue,index) {
return xxx;
};
["1", "2", "3"].map(parseInt)
||
["1", "2", "3"].map(function parseInt(currentValue,index) {
return xxx;
})
||
["1", "2", "3"].map(function callback(currentValue,index) {
return parseInt(currentValue,index);
})
当currentValue
为1
时 return parseInt(1,0)
当currentValue
为2
时 return parseInt(2,1)
当currentValue
为3
时 return parseInt(3,2)
在上面我们就分析了
parseInt("1",0);//返回 1
parseInt("2",1);//返回 NaN
parseInt("3",2);//返回 NaN
so 综上所述:["1", "2", "3"].map(parseInt)
= [1, NaN, NaN]