JavaScript アドバンス

JavaScript ArrayBuffer

1. ArrayBuffer とは?

ArrayBuffer は、固定されたメモリブロックであり、多くの場合「型付き配列(Typed Arrays)」を格納するために使用されます。

このブロックの上に、ビットを数値、バイト、またはその他のデータ型として解釈するさまざまなビュー(Views)を作成できます。

2. ArrayBuffer の生成

新しい ArrayBuffer を作成するには、new ArrayBuffer() を使用します。

実装例:
16バイトの ArrayBuffer を作成します。

// ArrayBuffer を作成
const myBuf = new ArrayBuffer(16);

// バイト単位の長さを取得
let len = myBuf.byteLength;
  • ArrayBuffer のサイズはバイト(Bytes)単位で指定します。
  • byteLength プロパティがそのサイズを表します。
  • 一度作成されると、サイズを変更することはできません。

3. ArrayBuffer へのアクセス

ArrayBuffer 自体には、データを「読み取る(Read)」または「書き込む(Write)」ためのメソッドは存在しません。

データにアクセスするには、必ずビュー(View)を使用する必要があります。
型付き配列(Typed Arrays)DataView は、ArrayBuffer に対して数値データを読み書きする手段を提供します。

一般的な型付き配列:

  • Uint8Array - 8ビット符号なし整数
  • Int16Array - 16ビット符号付き整数
  • Int32Array - 32ビット符号付き整数
  • Float32Array - 32ビット浮動小数点数
  • Float64Array - 64ビット浮動小数点数

4. Uint8Array の使用例

各 Uint8 は 1 バイトを使用します。

実装例:

// 8バイトの ArrayBuffer を作成
const myBuf = new ArrayBuffer(8);

// Uint8Array ビューを作成
const view = new Uint8Array(myBuf);

// 最大 8 つの値を書き込む
view[0] = 10;
view[2] = 128;
view[1] = 255;

// 値を読み取る
let v0 = view[0];
let v1 = view[1];
let v2 = view[2];

5. Int32Array の使用例

各 Int32 は 4 バイトを使用します。

実装例:

// 12バイトの ArrayBuffer を作成
const myBuf = new ArrayBuffer(12);

// Int32Array ビューを作成
const view = new Int32Array(myBuf);

// 12バイト = 最大 3 つの Int32 値を格納可能
view[0] = 100000;
view[1] = 200000;
view[2] = 300000;

// 値を読み取る
let v0 = view[0];
let v1 = view[1];
let v2 = view[2];

6. DataView の使用

DataView は、ArrayBuffer のためのより柔軟なビューです。
DataView を使用すると、異なる型(Int8, Uint16, Float32 など)の値を混在させて読み書きでき、任意のバイトオフセットで操作が可能です。

実装例:DataView による読み書き

// 8バイトの ArrayBuffer を作成
const myBuf = new ArrayBuffer(8);

// DataView を作成
const view = new DataView(myBuf);

// バイトオフセット 0 に 32ビット整数を書き込む
view.setInt32(0, 123456);

// バイトオフセット 4 に 16ビット整数を書き込む
view.setInt16(4, 32000);

// 値を読み取る
let v1 = view.getInt32(0);
let v2 = view.getInt16(4);
補足: DataView の各メソッドには、バイトオーダー(エンディアン)を制御するためのオプション引数 littleEndian (true/false) が存在します。

7. ArrayBuffer のスライス(Slicing)

slice() メソッドを使用すると、ArrayBuffer の一部のコピーを作成できます。指定された範囲のバイトを含む新しい ArrayBuffer が返されます。

実装例:ArrayBuffer.slice()

// 8バイトの ArrayBuffer を作成
const myBuf = new ArrayBuffer(8);

// Uint8Array を作成
const view = new Uint8Array(myBuf);

// 0 から 7 までの値を設定
for (let i = 0; i < view.length; i++) {
  view[i] = i;
}

// 2バイト目から 5バイト目(5は含まない)までのコピーを作成
const sliced = myBuf.slice(2, 5);
const slicedView = new Uint8Array(sliced);
  • slice() メソッドは新しいバッファを作成します。
  • コピーされたバッファは、元のバッファとメモリを共有しません。

8. 文字列の変換

8.1 文字列から ArrayBuffer への変換 (UTF-8)

function stringToArrayBuffer(str) {
  const encoder = new TextEncoder();
  return encoder.encode(str).buffer;
}

const myBuf = stringToArrayBuffer("Hello");
let len1 = myBuf.byteLength;

8.2 ArrayBuffer から 文字列への変換 (UTF-8)

function arrayBufferToString(buffer) {
  const decoder = new TextDecoder();
  return decoder.decode(new Uint8Array(buffer));
}

const encoder = new TextEncoder();
const myBuf = encoder.encode("Hello ArrayBuffer").buffer;

let text = arrayBufferToString(myBuf);

9. ArrayBuffer の共有 (SharedArrayBuffer)

標準的な ArrayBuffer は、デフォルトではスレッド(メインスレッドと Web Workers など)間で共有されません。
ワーカー間でメモリを共有するために、JavaScript は SharedArrayBuffer を提供しています。

これは ArrayBuffer と同様に動作しますが、その内容は共有可能であり、Atomics オブジェクトと組み合わせて使用されます。

実装例:SharedArrayBuffer の作成

let buffer;
// セキュリティ要件を満たしているか確認
if (Window.crossOriginIsolated) {
  buffer = new SharedArrayBuffer(16);
} else {
  buffer = new ArrayBuffer(16);
}

const sharedView = new Int32Array(buffer);

// 値の設定
sharedView[0] = 42;

let numb = sharedView[0];

       重要: ブラウザで SharedArrayBuffer を有効にするには、特定のセキュリティヘッダー(COOP/COEP)の設定が必要になる場合があります。

10. まとめ

  • ArrayBuffer は固定サイズのメモリブロックを表す低レベルオブジェクトです。
  • ArrayBuffer に直接読み書きすることはできず、必ずビュー(型付き配列または DataView)を介してアクセスします。
  • 型付き配列は一律の数値データに適しており、DataView は混合データや構造化されたデータに適しています。
  • バッファの一部をコピーするには slice() を使用します。
  • 共有メモリによる並行処理には SharedArrayBuffer と Atomics を使用します。