インデックス付きコレクション

本章では、インデックス値により順序付けされたデータからなるコレクションを紹介します。配列、そして Array オブジェクトや TypedArray オブジェクトといった配列用の構造体があります。

Array オブジェクト

配列は名前やインデックスで参照できる値からなる順序付け集合です。例えば、従業員番号によってインデックスされ、従業員の名前が入った emp と呼ばれる配列を作れます。そして、emp[1] が従業員番号 1 、emp[2] が従業員番号 2 、……といった具合に。

JavaScript は明確な配列データ型を持っていません。しかしながら、アプリケーションで配列として機能する定義済みの Array オブジェクトとそのメソッドを利用できます。Array オブジェクトには配列の結合、逆順への並べ替え、ソートといった様々な方法で配列を操作するメソッドがあります。また、配列の長さを特定したり正規表現で使用するプロパティなどがあります。

配列の生成

次の文によって同じ配列が作成されます :

var arr = new Array(element0, element1, ..., elementN);
var arr = Array(element0, element1, ..., elementN);
var arr = [element0, element1, ..., elementN];

element0, element1, ..., elementN は配列要素となる値から構成されるリストです。これらの値が指定されると、この配列の要素はそれらの値に初期化されます。配列の length プロパティは引数の数に設定されます。

角括弧による構文は「配列リテラル」または「配列初期化子」と呼ばれます。この構文はその他の形式による配列作成よりも短いため、一般的に好まれる方法です。詳細については、配列リテラルの章をご覧ください。

非ゼロの長さを持つが、アイテムのない配列を生成するには、次のうちどちらかを使用します :

var arr = new Array(arrayLength);
var arr = Array(arrayLength);

// この方法はちょうど同じ結果になります
var arr = [];
arr.length = arrayLength;

注記 : 上記のコードでは、arrayLengthNumber 、つまり数値である必要があります。さもないと、単一の要素(指定した値)を持つ配列が生成されます。また、arr.length を呼ぶと arrayLength が返されますが、実際には配列は空要素 (undefined) で構成されます。配列上で for...in ループを実行しても配列要素は返されません。

上記のように配列を新規変数として定義する方法に加え、新規、あるいは既存のオブジェクトのプロパティに配列を割り当てることができます :

var obj = {};
// ...
obj.prop = [element0, element1, ..., elementN];

// あるいは、
var obj = {prop: [element0, element1, ...., elementN]}

1 個の要素で配列を初期化しようとして、その要素が Number である場合、角括弧構文を使用する必要があります。単一の Number 値が Array() コンストラクタや関数に渡されると、単一の数値要素としてではなく、arrayLength として解釈されます。

var arr = [42];      // 数 42 という要素を
                     // 1 個だけ持つ配列が作られる。

var arr = Array(42); // 要素がなく、arr.length が
                     // 42 に設定された配列が作られる。
                     // 以下のコードと同様 :
var arr = [];
arr.length = 42;

N の値が、小数部分が非ゼロの非整数である場合、Array(N) を呼び出すと、結果は RangeError になります。次のコードでこの動作を例示しています。

var arr = Array(9.3);  // RangeError: Invalid array length

任意のデータ型の単一の要素を持つ配列を作成したければ、配列リテラルを使用する方が安全です。あるいは、単一の要素を追加するより先に空の配列を作成しましょう。

配列へのデータ追加

要素に値を割り当てることで配列にデータを追加することができます。例えば、

var emp = [];
emp[0] = "Casey Jones";
emp[1] = "Phil Lesh";
emp[2] = "August West";

注記 : 上記コードで配列演算子(角括弧)内に非整数値を指定すると、配列要素ではなく配列を表すオブジェクト内のプロパティとして作成されます。以下の例をご覧ください。

var arr = [];
arr[3.4] = "Oranges";
console.log(arr.length);                // 0
console.log(arr.hasOwnProperty(3.4));   // true

配列を作成するときにも、データを追加することができます。:

var myArray = new Array("Hello", myVar, 3.14159);
var myArray = ["Mango", "Apple", "Orange"]

配列要素の参照

要素に付けられた序数を使って配列要素を参照することができます。例えば、次のような配列を定義しましょう :

var myArray = ["Wind", "Rain", "Fire"];

myArray[0] として配列の最初の要素に参照し、myArray[1] として配列の 2 番目の要素を参照します。要素のインデックスはゼロから始まります。

注記 : 配列演算子(角括弧)は配列のプロパティにアクセスする際にも使用できます(つまり JavaScript では配列はオブジェクトでもあります)。以下の例をご覧ください。

var arr = ["one", "two", "three"];
arr[2];  // three
arr["length"];  // 3

配列の長さについて理解する

実装レベルでは、JavaScript の配列はそのインデックス値をプロパティ名として使うことで、実際には標準のオブジェクトプロパティとして要素を格納しています。しかし length プロパティは特別です。すなわち、常に最終要素のインデックス値 + 1 を返します(次の例では、Dusty は 30 でインデックスされています。だから、cats.length は 30 + 1 を返します)。JavaScript の配列インデックスは 0 オリジン (0-based) です。すなわち、1 からではなく、0 から始まります。つまり、length プロパティは配列に格納されている最大インデックス値より 1 多い値になるということです :

var cats = [];
cats[30] = ['Dusty'];
console.log(cats.length); // 31

length プロパティに値を割り当てることもできます。格納されているアイテムの数より小さい値を設定すると、配列は切り捨てられます。すなわち、0 に設定すると完全に配列を空にします :

var cats = ['Dusty', 'Misty', 'Twiggy'];
console.log(cats.length); // 3

cats.length = 2;
console.log(cats); // "Dusty,Misty" がログ出力される - Twiggy は削除される

cats.length = 0;
console.log(cats); // ログは出力されない、配列 cats は空になる

cats.length = 3;
console.log(cats); // [undefined, undefined, undefined]

配列の反復処理

よく行われるのは配列の値に対する反復処理ですが、それぞれの値に対して処理を行う方法がいくつかあります。これを行う一番簡単な方法は次のとおり :

var colors = ['red', 'green', 'blue'];
for (var i = 0; i < colors.length; i++) {
  console.log(colors[i]);
}

配列内の要素がいずれも真偽値のコンテキストで false に評価されないことがわかっている場合 ― 例えば配列が DOM ノードのみで構成されている場合などには、例のように、より効率的なイディオムを使用できます :

var divs = document.getElementsByTagName('div');
for (var i = 0, div; div = divs[i]; i++) {
  /* Process div in some way */
}

この例では、配列の長さのチェックに掛かるオーバーヘッドを回避しています。そしてより便利に使えるように、ループの反復のたびに div 変数に現在のアイテムを代入するようにしています。

配列を反復処理する別の方法として forEach() メソッドがあります :

var colors = ['red', 'green', 'blue'];
colors.forEach(function(color) {
  console.log(color);
});

forEach に渡される関数では、その関数への引数に配列の要素が渡されて、配列内の各アイテムごとに 1 回ずつ実行されます。値が割り当てられていない要素は forEach ループで反復されません。

配列定義の際に省略された要素は、forEach によって反復処理されるときにはリストアップされませんが、配列要素に undefined が割り当てられている場合はリストアップされることに注意してください :

var array = ['first', 'second', , 'fourth'];

// returns ['first', 'second', 'fourth'];
array.forEach(function(element) {
  console.log(element);
})

if(array[2] === undefined) { console.log('array[2] is undefined'); } // true

var array = ['first', 'second', undefined, 'fourth'];

// returns ['first', 'second', undefined, 'fourth'];
array.forEach(function(element) {
  console.log(element);
})

JavaScript では、配列要素は標準的なオブジェクトプロパティとして保存されるので、for...in ループを使って JavaScript 配列を反復処理するのはお勧めできません。というのも、通常の要素とすべての列挙プロパティがリストアップされるからです。

配列のメソッド

Array オブジェクトには以下のようなメソッドがあります :

concat() は 2 つの配列を結合し、新しい配列を返します。

var myArray = new Array("1", "2", "3");
myArray = myArray.concat("a", "b", "c"); 
// myArray は ["1", "2", "3", "a", "b", "c"] になる

join() は配列のすべての要素を文字列に結合します。

var myArray = new Array("Wind", "Rain", "Fire");
var list = myArray.join(" - "); // list には "Wind - Rain - Fire" が代入される

push() は 1 個以上の要素を配列の最後に追加し、その結果得られる配列の長さを返します。

var myArray = new Array("1", "2");
myArray.push("3"); // myArray は ["1", "2", "3"] になる

pop() は配列から最後の要素を取り除き、その要素を返します。

var myArray = new Array("1", "2", "3");
var last = myArray.pop(); 
// myArray は ["1", "2"] に、 last は "3" となる

shift() は配列から最初の要素を取り除き、その要素を返します。

var myArray = new Array ("1", "2", "3");
var first = myArray.shift(); 
// myArray は ["2", "3"]に、first は "1" になる

unshift() は 1 個以上の要素を配列の先頭に追加し、その新しい配列の長さを返します。

var myArray = new Array ("1", "2", "3");
myArray.unshift("4", "5"); 
// myArray は ["4", "5", "1", "2", "3"] となる

slice(start_index, upto_index) は配列の一部を抽出し、新しい配列を返します。

var myArray = new Array ("a", "b", "c", "d", "e");
myArray = myArray.slice(1, 4); // インデックス値 1 からスタートし
                               // インデックス値 3 までのすべての要素を抽出、[ "b", "c", "d"] を返す

splice(index, count_to_remove, addElement1, addElement2, ...) は要素を配列から取り除き、(必要に応じて)置き換えます。

var myArray = new Array ("1", "2", "3", "4", "5");
myArray.splice(1, 3, "a", "b", "c", "d"); 
// myArray は ["1", "a", "b", "c", "d", "5"] となる
// このコードではインデックス値 1 の要素("2" がある場所)からスタートし、
// 3 個の要素を削除して、その場所に
// 連続した要素すべてを挿入する

reverse() は配列の要素を逆順に入れ替えます。最初の配列要素は最後に、最後の配列要素は最初になります。

var myArray = new Array ("1", "2", "3");
myArray.reverse(); 
// 配列要素が入れ替えられて、myArray = [ "3", "2", "1" ] となる

sort() は配列要素をソートします。

var myArray = new Array("Wind", "Rain", "Fire");
myArray.sort(); 
// 配列がソートされて、myArray = [ "Fire", "Rain", "Wind" ] となる

sort() は配列要素をどのように比較されるかを判定するコールバック関数も受け取ります。コールバック関数は 2 つの値を比較し、3 つの値のうち 1 つを返します。
例えば、次では、文字列の最後の文字によってソートします :

var sortFn = function(a, b){
  if (a[a.length - 1] < b[b.length - 1]) return -1;
  if (a[a.length - 1] > b[b.length - 1]) return 1;
  if (a[a.length - 1] == b[b.length - 1]) return 0;
}
myArray.sort(sortFn); 
// sorts the array so that myArray = ["Wind","Fire","Rain"]
  • このソートシステムにより ab より小さいとされた場合、-1 (または、任意の負の数)を返します。
  • このソートシステムにより ab より大きいとされた場合、1 (または、任意の正の数)を返します。
  • ab が等値と見なされる場合、0 を返します。

indexOf(searchElement[, fromIndex]) は配列から searchElement を検索します。そして、最初にマッチした位置のインデックスを返します。

var a = ['a', 'b', 'a', 'b', 'a'];
console.log(a.indexOf('b')); // 1 がログ出力される
// 最後にマッチした位置の後から検索を再開する
console.log(a.indexOf('b', 2)); // 3 がログ出力される
console.log(a.indexOf('z')); // 'z' は見つからないので -1 がログ出力される

lastIndexOf(searchElement[, fromIndex])indexOf のように動作します。しかし、最後の要素から開始して後方に検索します。

var a = ['a', 'b', 'c', 'd', 'a', 'b'];
console.log(a.lastIndexOf('b')); // 5 がログ出力される
// 最後にマッチした位置の前から検索を再開する
console.log(a.lastIndexOf('b', 4)); // 1 がログ出力される
console.log(a.lastIndexOf('z')); // -1 がログ出力される

forEach(callback[, thisObject]) はすべての配列アイテムにコールバック関数 callback を実行します。

var a = ['a', 'b', 'c'];
a.forEach(function(element) { console.log(element);} ); 
// 順番にそれぞれのアイテムをログ出力する

map(callback[, thisObject]) はすべての配列アイテムごとにコールバック関数 callback を実行し、戻り値からなる新しい配列を返します。

var a1 = ['a', 'b', 'c'];
var a2 = a1.map(function(item) { return item.toUpperCase(); });
console.log(a2); // A,B,C がログ出力される

filter(callback[, thisObject]) はコールバック関数 callback が true を返すアイテムからなる新しい配列を返します。

var a1 = ['a', 10, 'b', 20, 'c', 30];
var a2 = a1.filter(function(item) { return typeof item == 'number'; });
console.log(a2); // logs 10,20,30

every(callback[, thisObject]) はコールバック関数 callback が配列内のすべてのアイテムで true を返す場合に true を返します。

function isNumber(value){
  return typeof value == 'number';
}
var a1 = [1, 2, 3];
console.log(a1.every(isNumber)); // logs true
var a2 = [1, '2', 3];
console.log(a2.every(isNumber)); // logs false

some(callback[, thisObject]) はコールバック関数 callback が配列内の少なくとも一つのアイテムで true を返す場合に true を返します。

function isNumber(value){
  return typeof value == 'number';
}
var a1 = [1, 2, 3];
console.log(a1.some(isNumber)); // logs true
var a2 = [1, '2', 3];
console.log(a2.some(isNumber)); // logs true
var a3 = ['1', '2', '3'];
console.log(a3.some(isNumber)); // logs false

コールバック関数を受け取る上記のメソッドは反復メソッド (iterative method) として知られています。というのも、いずれも何らかの形で配列全体にわたって反復処理するからです。各アイテムは必要に応じて thisObject と呼ばれる第二引数を受け取ります。この引数が与えられた場合、thisObject はコールバック関数の本体内では this キーワードが持つ値となります。与えられない場合は、関数が明示的にオブジェクトコンテキストの外側で呼び出された場合と同様に、this はグローバルオブジェクト (window) を参照します。

コールバック関数は実際は 3 つの引数で呼びだされます。第一引数は現在のアイテムの値、第二引数は配列のインデックス、 第三引数は配列自身への参照です。JavaScript の関数はパラメータリストで指定されなかった引数は無視します。ですから、alert のような単一の引数のみを受け取る関数でも問題なくコールバック関数とすることができます。

reduce(callback[, initialValue]) はアイテムリストを単一の値に還元するためのコールバック関数 callback(firstValue, secondValue) を適用します。

var a = [10, 20, 30];
var total = a.reduce(function(first, second) { return first + second; }, 0);
console.log(total) // 60 が出力される

reduceRight(callback[, initalvalue])reduce() のように機能します。しかし最後の要素から適用を開始します。

reducereduceRight もある意味では配列の反復メソッドです。数列を単一の値に還元する際、再帰的に2つの値を組み合わせるアルゴリズムにこれらのメソッドを使用してください。

多次元配列

配列をネストすることができます、つまり配列要素として配列を含めることができることを意味します。JavaScript の配列の特徴を活かして、多次元配列を生成できます。

以下のコードでは 2 次元配列を作成しています。

var a = new Array(4);
for (i = 0; i < 4; i++) {
  a[i] = new Array(4);
  for (j = 0; j < 4; j++) {
    a[i][j] = "[" + i + "," + j + "]";
  }
}

この例では、次のテーブル行を持つ配列を作成しています :

Row 0: [0,0] [0,1] [0,2] [0,3]
Row 1: [1,0] [1,1] [1,2] [1,3]
Row 2: [2,0] [2,1] [2,2] [2,3]
Row 3: [3,0] [3,1] [3,2] [3,3]

配列と正規表現

配列が正規表現と文字列との間のマッチ結果である場合、その配列はマッチについての情報を提供するプロパティと要素を返します。RegExp.exec()String.match()String.split() による戻り値がこうした配列となります。正規表現とともに配列を使用する際の情報については、当ガイドの正規表現の章をご覧ください。

配列様のオブジェクトを利用する

document.getElementsByTagName() によって返される NodeList や、関数本体内で利用できる arguments オブジェクトのように、表面上は配列のようにふるまう JavaScript オブジェクトがありますが、これらは関数メソッドすべてを共有してはいません。例えば、arguments オブジェクトには length 属性がありますが、forEach() メソッドは実装されていません。

その他の配列様オブジェクトとは対照的に、Array プロトタイプメソッドは呼び出しが可能です。例えば :

function printArguments() {
  Array.prototype.forEach.call(arguments, function(item) {
    console.log(item);
  });
}

その上 Array プロトタイプメソッドは文字列上で利用できるので、配列と同じ方法でこれらの文字に順次アクセスできます :

Array.prototype.forEach.call("a string", function(chr) {
  console.log(chr);
});

型付き配列

JavaScript の型付き配列は配列様のオブジェクトで、未加工のバイナリデータにアクセスする仕組みをもたらします。ご存知のように、 Array オブジェクトは動的に拡大、縮小し、JavaScript におけるいかなる値でも保持することができます。JavaScript エンジンは最適化を行うため、これらの配列は高速に機能します。しかし、オーディオやビデオ操作といった機能が追加され、WebSocket を使い未加工のデータにアクセスするなど、Webアプリケーションはさらにパワフルなものとなってきました、そのため JavaScript コードが型付き配列内の未加工バイナリデータを手早く簡単に操作できれば有益である場合がよくある、ということが明らかになってきました。

バッファとビュー : 型付き配列のアーキテクチャ

最大の柔軟性と効率性を達成するため、JavaScript 型付き配列の実装をバッファビューに分離しました。バッファ(ArrayBuffer オブジェクトによる実装)はデータのかたまりを表すオブジェクトです。対話を行うためのフォーマットではなく、データの中身にアクセスするためのメカニズムを提供しません。バッファに含まれる記録にアクセスするには、ビューを使用する必要があります。ビューは実際の型付き配列からデータを送信するコンテキスト — つまり、データ型、オフセットの開始位置、要素数 — を提供します。

Typed arrays in an ArrayBuffer

ArrayBuffer

ArrayBuffer は汎用的な固定長のバイナリデータバッファを表すために使用されるデータ型です。ArrayBuffer の内容は直接操作できません。かわりに、型付き配列ビューか特定のフォーマットでバッファを表す {jsxref("DataView")}} を生成し、それらをバッファの内容の読み書きに使用します。

型付き配列ビュー

型付き配列ビューは自己記述的な名前を持っていて、そのすべてが Int8, Uint32, Float64 などといったよく見られる数値型用のビューを提供しています。Uint8ClampedArray という1つ特別な型付き配列ビューがあります。これは、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

詳細については、JavaScript 型付き配列と様々な TypedArray オブジェクトに関するレファレンスをご覧ください。

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

タグ: 
 このページの貢献者: YuichiKamiki, x2357, shide55
 最終更新者: YuichiKamiki,