JavaScript の型付き配列は配列状のオブジェクトであり、生のバイナリデータにアクセスする手段を提供します。すでにご存知のとおり、Array
オブジェクトは動的に拡大または縮小され、任意の JavaScript 値を持つことができます。JavaScript エンジンは、これらの配列を高速化するために最適化を実施します。一方、Web アプリケーションがより強力になり動画を操作する、あるいは WebSocket を使用して生データにアクセスするなどさまざまな機能が追加されるため、JavaScript コードがより速く動作する、また型付き配列により生のバイナリデータの操作が容易になることが有益であると考えられるのは明らかです。
ただし、型付き配列で Array.isArray()
を呼び出すと false
を返しますので、型付き配列と通常の配列を混同することはありません。また、通常の配列では使用できるが型付き配列ではサポートされないメソッドがあります (例えば push や pop)。
バッファとビュー: 型付き配列の構造
最大限の柔軟性と効率性を達成するために、JavaScript の型付き配列では バッファ と ビュー に実装を分けています。バッファ (ArrayBuffer
オブジェクトで実装) は、データの塊を表すオブジェクトです。これは特に形式がなく、またその中身にアクセスする手段を提供しません。バッファに格納されている情報にアクセスするには、ビューを使用することが必要です。ビューはコンテキスト (データの種類、開始位置のオフセット、要素の数) を提供し、データを実際の型付き配列に返します。
ArrayBuffer
ArrayBuffer
は、一般的な固定長のバイナリデータのバッファを示すために使用するデータ型です。ArrayBuffer
の内容物を直接操作することはできません。代わりにバッファを特定の形式で表現し、またバッファの内容物を読み書きするために使用する、型付き配列のビューまたは DataView
を作成します。
型付き配列のビュー
型付き配列のビューは自身を表現する名称を持ち、Int8
、Uint32
、Float64
などの一般的な数値型のビューを提供します。特別な型付き配列のビューとして 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]
でアクセスできます。
通常の配列に転換する
型付き配列を処理した後は、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 | 廃止された | ECMAScript 6 に置き換え |
ECMAScript 2015 (6th Edition, ECMA-262) TypedArray Objects の定義 |
標準 | ECMA 標準では最初の定義 |
ECMAScript 2017 Draft (ECMA-262) TypedArray Objects の定義 |
ドラフト |
ブラウザ実装状況
機能 | 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 |