JavaScript の型付き配列の基本
JavaScript の型付き配列の種類
型付き配列 (Typed Array) には次の種類があります。
型付き配列 | 要素のサイズ | 説明 |
---|---|---|
Int8Array | 1 | 8ビット符号付き整数 |
Uint8Array | 1 | 8ビット符号なし整数 |
Uint8ClampedArray | 1 | Clamped 変換有りの符号なし整数 |
Int16Array | 2 | 16ビット符号付き整数 |
Uint16Array | 2 | 16ビット符号なし整数 |
Int32Array | 4 | 32ビット符号付き整数 |
Uint32Array | 4 | 32ビット符号なし整数 |
BitInt64Array | 8 | 64ビット符号付き整数 |
BitUint64Array | 8 | 64ビット符号なし整数 |
Float32Array | 4 | 32ビットIEEE浮動小数点 |
Float64Array | 8 | 64ビットIEEE浮動小数点 |
BitInt64Array と BitUint64Array は 2020 年の仕様に含まれました。
JavaScript の型付き配列オブジェクトの生成
JavaScript の型付き配列オブジェクトは固定長の配列です。型付き配列を作成するときには、要素数を指定して作成します。
次の例では、要素数 4 個の Uint8Array オブジェクトを作成し、0 番目の要素と 3 番目の要素に値をセットしています。
let a = new Uint8Array(4)
console.log(a)
// Uint8Array [ 0, 0, 0, 0 ]
a[0] = 1
a[3] = 2
console.log(a)
// Uint8Array [ 1, 0, 0, 2 ]
型付き配列の要素数を指定する代わりに、 ArrayBuffer を渡して型付き配列を作成することもできます。
ArrayBuffer はバイト列を表すバッファです。ArrayBuffer のデータは直接操作することはできず、型付き配列や DataView に関連付けさせて使います。
次の例では 4 バイトの ArrayBuffer を作成し、それをバッファとする Uint16Array を作成しています。
let buffer = new ArrayBuffer(4)
let a = new Uint16Array(buffer)
console.log(a)
// Uint16Array [ 0, 0 ]
Uint16Array は 1 要素で 2 バイト必要なので、4 バイトのバッファを与えられた場合、2 つの要素を持つ Uint16Array オブジェクトが作成されます。
もし 2 の倍数でないバイト長の ArrayBuffer を渡して Uint16Array オブジェクトを作成しようとした場合は、 RangeError: byte length of Uint16Array should be a multiple of 2 というエラーが発生し、 Uint16Array オブジェクトは作成できません。
JavaScript の型付き配列と ArrayBuffer
型付き配列では、データを保存するためのバッファが必要です。バッファは ArrayBuffer 型で作成します。
コンストラクタで要素数を指定して型付き配列を作成した場合には、新しく ArrayBuffer が作成されて、型付き配列のバッファとして使われます。
型付き配列に関連付けされた ArrayBuffer には、 buffer プロパティからアクセスできます。
let a = new Uint16Array(2)
console.log(a.buffer)
// ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }
コンストラクタに ArrayBuffer を渡して型付き配列を作成した場合には、コンストラクタに渡した ArrayBuffer が型付き配列に関連付けされて使われます。
このため、ある型付き配列のバッファを渡して、新しく型付配列を作成した場合は、これらの二つの型付き配列オブジェクトは同じバッファを共有します。
let a = new Uint8Array(4)
a[0] = 1
a[3] = 2
console.log(a)
// Uint8Array [ 1, 0, 0, 2 ]
let a2 = new Int16Array(a.buffer)
console.log(a2)
// Int16Array [ 1, 512 ]
[1, 0, 0, 2] という内容のバッファを Int16Array 型付き配列で解釈すると、リトルエンディアンの環境では [ 1, 512 ] と評価されます。 Intel アーキテクチャはリトルエンディアンです。iPhone は ARM アーキテクチャでリトルエンディアンモードで実行されています。
JavaScript の型付き配列と DataView
DataView は ArrayBuffer と組み合わせて使い、 ArrayBuffer のデータを読み書きするために使います。
型付き配列のバッファは ArrayBuffer ですから、DataView を使うことで、型付き配列に関連付けされたバッファを操作することもできます。
データを読み書きする DataView のメソッドは get[型名]() (読み取り) または set[型名]() (書き込み) という形式です。 例えば指定したバッファを Uint16 として読み取るならば getUint16() というメソッドを使います。
このとき、リトルエンディアンとして読み書きするか、ビッグエンディアンとして読み書きするか指定するパラメータがあります。
次の例では a.buffer に関連付けされた DataView を作成して、そのバッファのデータをリトルエンディアンの 16ビット符号なし整数として読み取っています。
let a = new Uint8Array(4)
a[0] = 1
a[3] = 2
console.log(a)
// Uint8Array [ 1, 0, 0, 2 ]
let isLittleEndian = true
let dv = new DataView(a.buffer)
let m = dv.getUint16(0, isLittleEndian) // 0 はバッファ先頭からのオフセット
let n = dv.getUint16(2, isLittleEndian) // 2 はバッファ先頭からのオフセット
console.log(`m: ${m}, n:${n}`) // m: 1, n:512
エンディアンの指定をしないとビッグエンディアンとして扱われます。