map参数String.fromCharCode时的奇怪问题
上篇Array.from
技巧介绍时,出现一个奇怪问题...
# 问题描述
上篇利用Array.from生成指定范围序列是发现一个问题,在填充指定范围序列数组的时候,输出有点奇怪。
//生成指定范围的序列数组的方法
const range = (start, stop, step=1) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
// 字母序列
range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x));
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
正常的如此使用,没有问题;如果我们想简写,比如这样
[1,2,3].map(Math.sqrt);
//[1, 1.4142135623730951, 1.7320508075688772]
// 但是这样,输出居然不一样了,看起来一些字符后有些奇怪的东西如 "K↵"
range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(String.fromCharCode);
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J ", "K↵", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
乍一看,非常奇怪的问题。
# 原因分析
// 这样看的更清楚
JSON.stringify(range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(String.fromCharCode))
// "["A\u0000\u0000","B\u0001\u0000","C\u0002\u0000","D\u0003\u0000","E\u0004\u0000","F\u0005\u0000","G\u0006\u0000","H\u0007\u0000","I\b\u0000","J\t\u0000","K\n\u0000","L\u000b\u0000","M\f\u0000","N\r\u0000","O\u000e\u0000","P\u000f\u0000","Q\u0010\u0000","R\u0011\u0000","S\u0012\u0000","T\u0013\u0000","U\u0014\u0000","V\u0015\u0000","W\u0016\u0000","X\u0017\u0000","Y\u0018\u0000","Z\u0019\u0000"]"
每个元素后面都跟了一些奇怪的东西;其实仔细看看文档就知道发生了什么;我们看看定义
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
//可以看出,String.fromCharCode可以接收多个参数
String.fromCharCode(num1[, ...[, numN]])
仔细分析下,原因在于隐式参数的问题,map函数中会接收三个参数,(currentValue,index,array)第一是值,第二个是索引,第三个是数组自身;我们再看看String.fromCharCode这个函数,他也接收多个参数。
实际上String.fromCharCode调用时接收了两个参数,一个值,一个index,所以出现这样'看似奇怪'的输出。
这同样也解释了map(parseInt)为什么返回值会是这样
['1','1231','121323','121323'].map(parseInt)
// [1, NaN, 1, 16]
因为parseInt也会接收第二个index的参数,导致指定进制转换错误。
# 问题解决
[97,98,99].map(x => String.fromCharCode(x))
//["a", "b", "c"]
['1','21212','19'].map(x=>parseInt(x,10));
//[1, 21212, 19]
所以为了防止出现类似非预期结果,还是老老实实写完整,还需注意api的设计,日常虽然简写没有问题,特别情况下就会出问题,当然归根结底还是自己api使用的锅,习惯中常用用多了,忘记了api本来面目。