Hi~,我是 一碗周,一个在舒适区垂死挣扎的前端,如果写的文章有幸可以得到你的青睐,万分有幸~
面试官:['1', '2', '3'].map(parseInt)
的结果是什么?为甚?
我:[1, 2, 3]
。
面试官:你不用来了。
写在前面
今天看到一道题,['1', '2', '3'].map(parseInt)
的结果是什么?看到这个题下意识的觉得答案就是[1, 2, 3]
,但实际上,答案是[1, NaN, NaN]
,这是为什么呢?我们来一探究竟。
parseInt函数
首先我们来看一下parseInt()
函数,关于parseInt()
函数,MDN中是这样介绍的:parseInt(string, radix)
将一个字符串string
转换为radix
进制的整数, radix
为介于2-36
之间的数。返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回NaN
。
到这为止,我们对parseInt()
函数有了一个基础的了解,根据上面的描述,也就是说我们为parseInt()
的第二个参数传递一个非2-36
之间的数,返回结果是NaN
,我们来测试一下:
console.log(parseInt(10, 0)) // 10
console.log(parseInt(10, 1)) // NaN
console.log(parseInt(10, 37)) // NaN
按照我们的思路,这里的结果应该是3个NaN
,但实际并不是,关于radix
参数,在MDN中有明确的解释:
如果 radix 是 undefined、0或未指定的,JavaScript会假定以下情况:
1. 如果输入的 string以 "0x" 或 "0x"(一个0,后面是小写或大写的X)开头,那么radix被假定为16,字符串的其余部分被当做十六进制数去解析。
2. 如果输入的 string 以 "0"(0)开头, radix 被假定为8(八进制)或10(十进制)。具体选择哪一个radix取决于实现。ECMAScript 5 澄清了应该使用 10 (十进制),但不是所有的浏览器都支持。因此,在使用parseInt时,一定要指定一个 radix。
3. 如果输入的 string 以任何其他值开头, radix 是 10 (十进制)。
这就解释了我们的parseInt(10, 0)
的结果是10了。
Array.prototype.map方法
现在我们来了解一下map方法的作用,该方法接受两个参数,第一个是一个回调函数,数组中的每一项都会执行该函数,这个回调函数接受三个参数,第一个是正在处理的元素,第二个是正在处理的索引,第三个是当前数组;第二个参数是调用回调函数的this
。
下面代码中展示了Array.prototype.map
方法的基础用法:
function doubleNum(n, i) {
let doubleN = 2 * n
console.log(`第{i+1}个元素的的二倍是${doubleN}`)
return doubleN
}
let newArr = [1, 2, 3].map(doubleNum)
console.log(newArr)
/* 执行结果如下:
第{i+1}个元素的的二倍是2
第{i+1}个元素的的二倍是4
第{i+1}个元素的的二倍是6
[ 2, 4, 6 ]
*/
如果上面的写法看不懂,我们可以将函数移动一下位置,代码如下:
let newArr = [1, 2, 3].map(function (n, i) {
let doubleN = 2 * n
console.log(`第{i+1}个元素的的二倍是${doubleN}`)
return doubleN
})
解题
经过上面的介绍,现在我们应该已经知道的这个题的结果了,它的运行情况如下:
parseInt('1', 0)
,直接按照10进制解析,结果为1;parseInt('2', 1)
,传入了非2~36
的值,结果为NaN;parseInt('3', 2)
,按照2进制进行解析,2进制可以解析的数字只有1和0,所以返回NaN
。
知道了这一题的答案,我们来看一下下面这个代码片段,它的运行结果又是什么:
['10','10','10','10','10'].map(parseInt);
- 首先
parseInt('10', 0)
的结果是10,不用解释; - 然后
parseInt('10', 1)
的结果是NaN,我们前面也解释过了; parseInt('10', 2)
的结果是2,这是因为10被转换为二进制就是2;parseInt('10', 3)
的结果是3,10被转换为三进制就是3;parseInt('10', 4)
以此类推。
最终结果是[10, NaN, 2, 3, 4]
。