为何直接对TypedArray用map与转Array后用map的十六进制结果不同?
TypedArray.map与普通数组map结果不一致的原因解析
我们的目标是将字符串转换为十六进制,但发现直接对TypedArray调用map方法,与先通过Array.from将TypedArray转为普通数组后再调用map方法,得到的结果不一致。相关代码及运行结果如下:
var buf = new TextEncoder().encode('hello'); var ret = ''; for (var b of buf) ret += b.toString(16).padStart(2, '0').slice(-2); console.log( '\n', buf.join(), // 104,101,108,108,111 '\n', buf.map(x => x.toString(16).padStart(2, '0').slice(-2)).join(''), // 6865000 '\n', Array.from(buf).join(), // 104,101,108,108,111 '\n', Array.from(buf).map(x => x.toString(16).padStart(2, '0').slice(-2)).join(''), // 68656c6c6f '\n', ret, // 68656c6c6f '\n', decodeURIComponent('%' + ret.match(/.{1,2}/g).join('%')) // hello ); /* 104,101,108,108,111 6865000 104,101,108,108,111 68656c6c6f 68656c6c6f hello */
核心原因
TypedArray的map方法会保留原数组的类型,它会把回调函数的返回值强制转换为原TypedArray的元素类型;而普通数组的map没有类型约束,会直接保留回调的返回结果。
具体分析
buf是TextEncoder.encode生成的Uint8Array,每个元素都是0-255的整数。- 调用
buf.map时,回调返回的是十六进制格式的字符串(比如"68"、"6c"):- 对于纯数字字符串(如
"68"),Uint8Array会将其转为对应的整数68,这一步没问题; - 对于包含字母的十六进制字符串(如
"6c"),直接转整数会被识别为十进制,parseInt("6c")结果是NaN,而Uint8Array会把NaN强制转为0; - 最终
buf.map返回的Uint8Array元素是[68, 65, 0, 0, 0],拼接后就是"6865000"。
- 对于纯数字字符串(如
Array.from(buf)会把Uint8Array转为普通数组,普通数组的map不会做类型转换,回调返回的字符串会被完整保留,因此得到正确的十六进制拼接结果"68656c6c6f"。
内容的提问来源于stack exchange,提问作者vokeio
相关产品推荐
相关产品推荐

