JavaScript の型付き配列は配列状のオブジェクトであり、生のバイナリデータにアクセスする手段を提供します。すでにご存知のとおり、Array オブジェクトは動的に拡大または縮小され、任意の JavaScript 値を持つことができます。JavaScript エンジンは、これらの配列を高速化するために最適化を実施します。一方、Web アプリケーションがより強力になり動画を操作する、あるいは WebSocket を使用して生データにアクセスするなどさまざまな機能が追加されるため、JavaScript コードがより速く動作する、また型付き配列により生のバイナリデータの操作が容易になることが有益であると考えられるのは明らかです。

ただし、型付き配列で Array.isArray() を呼び出すと false を返しますので、型付き配列と通常の配列を混同することはありません。また、通常の配列では使用できるが型付き配列ではサポートされないメソッドがあります (例えば push や pop)。

バッファとビュー: 型付き配列の構造

最大限の柔軟性と効率性を達成するために、JavaScript の型付き配列では バッファビュー に実装を分けています。バッファ (ArrayBuffer オブジェクトで実装) は、データの塊を表すオブジェクトです。これは特に形式がなく、またその中身にアクセスする手段を提供しません。バッファに格納されている情報にアクセスするには、ビューを使用することが必要です。ビューはコンテキスト (データの種類、開始位置のオフセット、要素の数) を提供し、データを実際の型付き配列に返します。

Typed arrays in an ArrayBuffer

ArrayBuffer

ArrayBuffer は、一般的な固定長のバイナリデータのバッファを示すために使用するデータ型です。ArrayBuffer の内容物を直接操作することはできません。代わりにバッファを特定の形式で表現し、またバッファの内容物を読み書きするために使用する、型付き配列のビューまたは DataView を作成します。

型付き配列のビュー

型付き配列のビューは自身を表現する名称を持ち、Int8Uint32Float64 などの一般的な数値型のビューを提供します。特別な型付き配列のビューとして Uint8ClampedArray があります。これは、値を 0 から 255 の間に制限します。例えば Canvas のデータ処理に役立ちます。

サイズ (バイト数) 説明 Web IDL 型 同等の C 型
Int8Array 1 8 ビット長、2 の補数方式の符号付き整数値 byte int8_t
Uint8Array 1 8 ビット長、符号なし整数値 octet uint8_t
Uint8ClampedArray 1 8 ビット長、符号なし整数値 (切り詰め) octet uint8_t
Int16Array 2 16 ビット長、2 の補数方式の符号付き整数値 short int16_t
Uint16Array 2 16 ビット長、符号なし整数値 unsigned short uint16_t
Int32Array 4 32 ビット長、2 の補数方式の符号付き整数値 long int32_t
Uint32Array 4 32 ビット長、符号なし整数値 unsigned long uint32_t
Float32Array 4 32 ビット長、IEEE 方式 浮動小数点数 unrestricted float float
Float64Array 8 64 ビット長、IEEE 方式 浮動小数点数 unrestricted double double

DataView

DataView は、任意のデータをバッファに読み書きするための getter/setter API を提供する、ローレベルインターフェイスです。これは、例えばさまざまな型のデータを扱う場合に役立ちます。型付き配列のビューは、プラットフォームのネイティブのバイトオーダ (Endianness) になります。DataView では、バイトオーダを制御できます。デフォルトはビッグエンディアンですが、getter/setter メソッドでリトルエンディアンに設定できます。

型付き配列を使用する Web API

FileReader.prototype.readAsArrayBuffer()
FileReader.prototype.readAsArrayBuffer() メソッドは、指定した Blob または File の内容物の読み取りを開始します。
XMLHttpRequest.prototype.send()
XMLHttpRequest のインスタンスの send() メソッドが、型付き配列と ArrayBuffer オブジェクトを引数としてサポートしました。
ImageData.data
これは 0 から 255 の間の整数値である、RGBA データを持つ一次元配列を表す Uint8ClampedArray です。

バッファと合わせてビューを使用する

始めにバッファの作成が必要であり、ここでは 16 バイト固定長とします:

var buffer = new ArrayBuffer(16);

これで、全体が 0 で初期化されたメモリ領域ができました。しかし、そのバッファに対してできることはあまりありません。バッファが実際に 16 バイトの大きさであることを確認する程度のことはできます:

if (buffer.byteLength === 16) {
  console.log("Yes, it's 16 bytes.");
} else {
  console.log("Oh no, it's the wrong size!");
} 

このバッファで実際の作業を行う前に、ビューを作成しなければなりません。バッファ内のデータを 32 ビット符号付き整数値の配列として扱うビューを作成してみましょう:

var int32View = new Int32Array(buffer);

この時点で配列のフィールドへ、通常の配列と同じようにアクセスすることが可能になります:

for (var i = 0; i < int32View.length; i++) {
  int32View[i] = i * 2;
}

これは配列を値 0, 2, 4, 6 の 4つのエントリ (4 つのエントリが各 4 バイトで、合計 16 バイト) で埋めます。

同一のデータに対する複数のビュー

同一のデータに対して複数のビューを作成できることを考えると、それらは実に興味深いものになります。例えば、前出のコードの続きを以下のようにします:

var int16View = new Int16Array(buffer);

for (var i = 0; i < int16View.length; i++) {
  console.log("Entry " + i + ": " + int16View[i]);
}

ここでは、同一のバッファを既存の 32 ビット値のビューと共有する 16 ビット整数値のビューを作成して、バッファ内の値すべてを 16 ビット整数値として出力しています。すると、0, 0, 2, 0, 4, 0, 6, 0 という出力を得ます。

ここで一歩進みましょう。以下のコードについて考えてみてください:

int16View[0] = 32;
console.log("Entry 0 in the 32-bit array is now " + int32View[0]);

このコードの出力は "Entry 0 in the 32-bit array is now 32" になります。言い換えると、2 つの配列は同じデータバッファを異なる形式で取り扱う単純なビューであるということです。同様のことを、任意のビュー型で行うことができます。

複合データ構造を扱う

1 つのバッファを、バッファ内において異なるオフセットで始まり、またタイプが異なる複数のビューと結びつけることで、複数の種類のデータを持つデータオブジェクトを取り扱うことが可能になります。これにより、例えば WebGL の複合データ構造、データファイル、js-ctypes を使用する際に必要な C 構造体を取り扱うことが可能になります。

以下の C 構造体について考えてみましょう:

struct someStruct {
  unsigned long id;
  char username[16];
  float amountDue;
};

このような形式のデータを含むバッファは、以下のようにアクセスできます:

var buffer = new ArrayBuffer(24);

// ... read the data into the buffer ...

var idView = new Uint32Array(buffer, 0, 1);
var usernameView = new Uint8Array(buffer, 4, 16);
var amountDueView = new Float32Array(buffer, 20, 1);

例えば、合計金額には amountDueView[0] でアクセスできます。

注記: C 構造体におけるデータ構造の配置は機種依存です。これらのデータ埋め込みの違いに注意および配慮してください。

通常の配列に転換する

型付き配列を処理した後は、Array プロトタイプの利点を享受するため通常の配列に変換することが、有用な場合があります。これは Array.from を使用する、あるいは Array.from がサポートされていなければ以下のコードを使用して実現できます。

var typedArray = new Uint8Array([1, 2, 3, 4]),
    normalArray = Array.prototype.slice.call(typedArray);
normalArray.length === 4;
normalArray.constructor === Array;

仕様

仕様書 策定状況 コメント
Typed Array Specification Obsolete ECMAScript 6 に置き換え
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'TypedArray Objects' in that specification.
Standard ECMA 標準では最初の定義

ブラウザ実装状況

機能 Chrome Firefox (Gecko) Internet Explorer Opera Safari
基本サポート 7.0 4.0 (2) 10 11.6 5.1
機能 Android Android 版 Chrome Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
基本サポート 4.0 (有) 4.0 (2) 10 11.6 4.2

関連情報

ドキュメントのタグと貢献者

タグ: 
 このページの貢献者: yyss, ethertank, kohei.yoshino, Yukoba, saneyuki_s, hATrayflood
 最終更新者: yyss,