potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

JavaScript TypedArrayのmapメソッドの注意(強制的な型変換)

  • TypedArray.prototype.map(...)
    • 変換結果がUint8→予想通りの結果
    • 変換結果が文字列等→予想外の結果(e.g. [0, 0, 0, ...]

TypedArray.prototype.mapの戻り値はTypedArrayであり、各要素はTypedArrayの要素型に変換されます。例えばUint8Array.prototype.mapメソッドの戻り値はUint8Arrayであり、各要素はUint8へ変換されます。Arraymapメソッドと同じ感覚で文字列へ変換した場合、戻り値はすべて0のTypedArrayになります。

上記は[...Array]Array.from関数、Array関数でArray型へ変換することで回避できます。ただし、変換のコストはかかります。

const uint8Array1 = Uint8Array.from([0, 1, 2, 3, 4]);
console.log(uint8Array1);
// Uint8Array(5) [ 0, 1, 2, 3, 4 ]

// 次のコードは一見成功してしまう。
// 実際にはtoStringで作成された文字列"X"がUint8へキャストされている。
console.log(uint8Array1.map(x => x.toString()));
// Uint8Array(5) [ 0, 1, 2, 3, 4 ]

// 次のコードは失敗する。
// toStringで作成された文字列"0xXX"がUint8へキャストされてすべて0になる。
console.log(uint8Array1.map(x => "0x"+x.toString(16).padStart(2, '0')));
// Uint8Array(5) [ 0, 0, 0, 0, 0 ]

// 一度Arrayへ変換すれば成功する。ただし変換コストはかかる。
console.log([...uint8Array1].map(x => "0x"+x.toString(16).padStart(2, '0')));
console.log(Array.from(uint8Array1).map(x => "0x"+x.toString(16).padStart(2, '0')));
// Array(5) [ "0x00", "0x01", "0x02", "0x03", "0x04" ]
// Array(5) [ "0x00", "0x01", "0x02", "0x03", "0x04" ]

参考