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本来面目。

最近更新
01
echarts扇形模拟镜头焦距与可视化角度示意图
03-10
02
vite插件钩子
03-02
03
vite的依赖预构建
02-13
更多文章>