配列はオブジェクトの一種であり、データ型としてはオブジェクトです。
配列を生成して初期化する方法を3つ紹介します。なおサンプルコードは、すべて同一の結果となります。
方法 | サンプルコード |
---|---|
コンストラクタ |
var a = new Array(); a[ 0 ] = 1.0; a[ 1 ] = 'text'; |
引数付きコンストラクタ |
var a = new Array( 1.0, 'text' ); |
var a = new Array( 2 ); a[ 0 ] = 1.0; a[ 1 ] = 'text'; |
|
配列リテラル |
var a = []; a[ 0 ] = 1.0; a[ 1 ] = 'text'; |
var a = [ 1.0, 'text' ]; |
Array()コンストラクタ関数を使用します。配列の生成後に未定義の要素に代入することで、配列の要素が生成され初期化されます。
Array()の引数に配列要素を与えることで、配列の生成時に初期化できます。
なお引数に数値を1つだけ指定した場合には、それが配列の長さとみなされ、その個数の未定義の要素を持った配列が生成されます。
全体を角かっこ ( [ ] ) で囲み、値をカンマで区切って記述します。
[ value, value, ... ]
最後の要素の後にカンマ (,) を付けると、IE9より前では要素の数が1つ増加します。これは他の環境とは異なる結果となるため、クロスブラウザとするためには最後にカンマを付けるべきではありません。同様の問題はオブジェクトリテラルにもあります。Trailing commas in JavaScript - Stack Overflow
たとえば配列aが、
var a = [ 1,2,3, ];
のように生成されたとすると、
alert( a.length ); alert( a[ a.length - 1 ] );
としたときの各ブラウザの出力は
ブラウザ | a.length |
a[ a.length - 1 ] |
---|---|---|
IE8 | 4 | undefined |
IE9 | 3 | 3 |
Firefox |
のように、異なる結果となります。
未定義の要素に代入することで、要素を追加できます。
a[ 10 ] = 1;
配列の最初や最後に要素を追加するならば、次項のunshift()やpush()を使用します。一方で特定の位置へ挿入するならば、splice()を用います。
簡単には、削除はdelete演算子で行えます。
var a = [ 1, 2, 3, 4, 5 ]; delete a[ 2 ]; // a [1, 2, undefined, 4, 5] alert( 2 in a ); // false alert( a.length ); // 5
こうすることで配列からその要素は除かれますが、配列の大きさは変わりません。一方で、削除する要素にundefinedを代入する方法もありますが、
var a = [ 1, 2, 3, 4, 5 ]; a[ 2 ] = undefined; // a [1, 2, undefined, 4, 5] alert( 2 in a ); // true alert( a.length ); // 5
この方法では要素は削除されず、配列の大きさも変わりません。よって確実に要素を削除するには、後述するsplice()を用います。
var a = [ 1, 2, 3, 4, 5 ];
a.splice( 2, 1 );
// a [1, 2, 4, 5]
すべての要素を削除するならば、新たに作成した空の配列を代入するのが簡単です。
var a = [ 1, 2, 3, 4, 5 ];
a = [];
// a []
push()とpop()で、先入れ後出し (FILO / または後入れ先出し (LIFO)) の機能を実現できます。
位置 | 操作 | メソッド |
---|---|---|
先頭 | 追加 | unshift |
削除 | shift | |
最後 | 追加 | push |
削除 | pop |
array.push( value, ... )Array.push - JavaScript | MDN
push()では複数の引数を与えることで、多数の項目を一度に追加できます。
var a = [ 1, 2 ]; a.push( 3 ); // [ 1, 2, 3 ] a.push( 10, 'a' ); // [ 1, 2, 3, 10, 'a' ]
引数に配列が含まれるときには、その配列のまま追加されます。それを要素に展開して追加するにはconcat()を使用します。
var a = [ 1, 2 ];
var b = [ 3, 4 ];
a.push( b ); // [1, 2, [3, 4]]
push()とは逆に、要素を取り除くのがpop()です。
array.pop()Array.prototype.pop - JavaScript | MDN
pop()では最後の1つの要素が返され、その要素が配列から削除されます。最後の要素まで削除され1つも要素を持たなくなると、undefinedが返されます。
var a = [ 1, 2, 3 ]; a.pop(); // 3が返され、aは[ 1, 2 ]となる a.pop(); // 2が返され、aは[ 1 ]となる a.pop(); // 1が返され、aは[]となる a.pop(); // undefinedが返され、aは[]のまま
array.splice( start, deleteCount, value, ... )Array.splice - JavaScript | MDN
挿入、削除そして置換を行います。
splice()とslice()を混同しない。slice()は配列の一部を切り取るメソッドです。
startに負数を指定した場合には、配列の終端から数えた要素となります。たとえば-1とすれば末尾の要素であり、これはarray.length+startの位置と等しくなります。
この関数は削除した要素を含む配列を返します。削除したのが1つの要素だけであっても、その要素を返すのではなく、その要素を含む配列を返します。
var a = [ 1, 2, 3, 4, 5 ]
としたときの実行結果を、下表にまとめます。
コード | 実行結果 |
---|---|
a.splice( 3 ); |
[4,5]を返し、aは[1,2,3]となる |
a.splice( -3 ); |
[3,4,5]を返し、aは[1,2]となる |
a.splice( 1, 3 ); |
[2,3,4]を返し、aは[1,5]となる |
a.splice( 1, 1 ); |
[2]を返し、aは[1,3,4,5]となる |
a.splice( 1, 10 ); |
[2,3,4,5]を返し、aは[1]となる |
a.splice( 2, 2, 10 ); |
[3,4]を返し、aは[1,2,10,5]となる |
a.splice( 2, 0, 10 ); |
[]を返し、aは[1,2,10,3,4,5]となる |
インデックスをブラケット表記法で指定することで、配列の要素へアクセスできます。
a[ 0 ];
識別子の先頭に数字を指定することは認められないため、これを
a.0;
のようには記述できません。
インデックスは内部的に文字列として処理されるため、その記述方法によっては予期せぬ結果を返すことがあります。
var a = [ 1, 2, 3 ]; alert( a[ 1 ] ); // 2 alert( a[ '1' ] ); // 2 alert( a[ 01 ] ); // 2 alert( a[ '01' ] ); // undefined
このことは、これらのインデックスの記述を文字列に変換してみることで、その違いを確かめられます。
alert( ( 1 ).toString() ); // '1' alert( ( '1' ).toString() ); // '1' alert( ( 01 ).toString() ); // '1' alert( ( '01' ).toString() ); // '01'
初期化していない要素や範囲外の要素から読み込むと、undefinedが返されます。
var a = new Array( 1 ); alert( a[ 0 ] ); // undefined alert( a[ 1 ] ); // undefined
またundefined演算子などで削除された要素も、undefinedを返します。
var a = [ 1, 2, 3 ]; alert( a[ 1 ] ); // 2 delete a[ 1 ]; alert( a[ 1 ] ); // undefined
var index = array.indexOf( searchElement[, fromIndex ] );Array.prototype.indexOf - JavaScript | MDN
このメソッドでは同値演算子によってsearchElementと等しいことを判定し、一致した最初の要素のインデックスを返します。一致しなかった場合には、-1が返されます。
var a = [ 1, 'a', 'A' ]; a.indexOf( 'A' ); // 2 a.indexOf( 'B' ); // -1
このindexOf()は、IE9以降でサポートされます。Browser compatibility - Array.prototype.indexOf() - JavaScript | MDN
指定インデックスの要素が存在するかどうかは、in演算子で確認できます。
指定値の要素が存在するかどうかは、前項のindexOf()で確認します。
alert( 2 in [10,20,30] ); // true alert( 2 in [10,20] ); // false
またはその要素を参照し、undefinedを返すかどうかで判定する方法もあります。
var a = [ 'a', 'b', undefined, 'd' ]; alert( a[1] ); // 'b' alert( a[2] ); // undefined alert( a[4] ); // undefined alert( typeof a[1] === 'undefined' ); // false alert( typeof a[2] === 'undefined' ); // true alert( typeof a[4] === 'undefined' ); // true
ただしこのように、その要素が値としてundefinedを持つときは正しく判定できません。
関数を利用して、条件に一致する要素が存在するか確認できます。
var someElementPassed = array.some( callback[, thisObject] );Array.some - JavaScript | MDN
arrayの1つずつの要素を引数として、callbackがくり返し呼ばれます。そのときcallbackがtrueを返した時点で、some()はtrueを返します。すべての要素に対してcallbackがfalseを返すと、some()はfalseを返します。
配列はオブジェクトであるため、代入演算子では参照のコピーとなります。
var a = [1, 2, 3]; var b = a; // 代入演算子によるコピー // a [1, 2, 3] // b [1, 2, 3] a[0]= 5; // a [5, 2, 3] // b [5, 2, 3] 配列aへの変更が、配列bにも反映されている
参照ではなく配列の要素をコピーするには、戻り値で新しい配列を返すメソッドを使用するのが簡単です。それは2つあります。
それぞれ次のように使用します。
var newArray = array.slice( 0 );
var newArray = array.concat();
これらはシャローコピーであるため、多次元配列では期待通りにコピーできません。
いずれの方法でも同じ結果が得られますが、その処理速度には違いがあります。copy array slice-vs-concat · jsPerfによる結果を信じるならば、slice(0)の方が高速なようです。
var a = [ [ 1, 2 ], [ 3, 4 ] ]; var b = a.slice( 0 ); // a [[1, 2], [3, 4]] // b [[1, 2], [3, 4]] a[0][0]= 5; // a [[5, 2], [3, 4]] // b [[5, 2], [3, 4]] 配列aへの変更が、配列bにも反映されている
Object.prototype.clone = function() { var newObj = ( this instanceof Array )? [] : {}; for( i in this ) { if( i == 'clone' ) continue; if( this[ i ] && typeof this[ i ] == 'object' ) { newObj[ i ] = this[ i ].clone(); } else { newObj[ i ] = this[ i ] } } return newObj; }
JavaScriptは多次元配列をサポートしていないため、配列の要素に配列を持たせることで、それに近い動作を実現します。
var a = new Array(); a[ 0 ] = new Array( 1, 2 ); a[ 1 ] = new Array( 3, 4 );
これは配列リテラルを用いれば、
var a = [ [ 1, 2 ], [ 3, 4 ] ];
のように記述しても同じです。
多次元配列の要素へのアクセスは、[]演算子をくり返すことで行います。たとえば先の配列に、
a[ 1 ][ 0 ];
とアクセスすれば、3が返されます。
JavaScriptでは配列のインデックスに文字列を使用できません。よって配列として連想配列はサポートされませんが、オブジェクトのプロパティでこれを代用できます。
仮にインデックスに文字列を使用した場合、それはArrayオブジェクトのプロパティとして認識され、配列の要素とはなりません。
以下のコードを実行してみます。
var array = new Array(); array[ 0 ] = 10; array[ 1 ] = 20; array[ 'a' ] = 30; array[ 'b' ] = 40; array[ 2 ] = 50;
デバッガで確認すると、'a'と'b'は配列として認識されていないことがわかります。また配列のサイズ (array.length) は3となります。
オブジェクトのプロパティ名を統一しておくことで、それをキーとしてArray.sort()メソッドでソートできます。
var array = new Array(); array.push( { key: 'alpha', value: 10 } ); array.push( { key: 'beta', value: 20 } ); array.push( { key: 'gamma', value: 5 } ); array.sort( function( a, b ) { return a.value - b.value; } );
for ... inの構文で、PHPなどのforeachに近い処理を実現できます。
変数 (下記の例ではi) に格納されるのは配列の要素ではなく、配列のインデックスもしくは連想配列のキーになります。なお、配列の要素を処理する順序は規定されていないめインデックス順に処理されるとは限らないことにも注意が必要です。
var array = new Array( 1, 2 );
array.foo = 'foo';
array[ 5 ] = 5;
array.push( 'a', 'b' );
for( var x in array )
{
document.write( array[ x ] + ',' );
}
// 1,2,5,a,b,foo, と出力
このように注意点が多いため、for ... in文はオブジェクトのプロパティをすべて処理する場合にだけ限定し、通常は
// arrayは上の定義に同じ for( var i = 0; i < array.length; i++ ) { document.write( array[ i ] + ',' ); } // 1,2,undefined,undefined,undefined,5,a,b, と出力
のようにfor文を用いるようにします。
JavaScript 1.6以降に対応した環境ならば、forEach()メソッドを利用できます。
array.forEach( callback[, thisArg ] )Array.prototype.forEach() - JavaScript | MDN
このメソッドではarrayの要素が1つずつ、callbackの関数へ渡されます。
配列全体を並べ替えるのに、sort()とreverse()という2つの組み込み関数が用意されています。
array.sort()sort | MDN
既定では、要素は文字列としてアルファベット順に並べ替えられます。要素が数値であっても文字列に変換されて比較されるため、この点には留意する必要があります。また順番は、厳密には文字エンコーディングによって決まる順となるため、たとえば['C','b','a']
を並べ替えると['C','a','b']
となります。
var array = [ 'C', 'b', 'B', 'b', 'a' ];
array.sort(); // ['B','C','a','b','b']
よって大文字/小文字の区別なくアルファベット順とするには、後述の比較関数を用いた上で、String.toUpperCase()で大文字に統一してから比較します。
array.sort( function( a, b ) // ['a','b','B','b','C']
{ return ( a.toUpperCase() > b.toUpperCase() )? 1 : -1; } );
ちなみに比較関数を指定しない場合の比較方法は、次のような関数を指定する場合と等しいです。
array.sort( function( a, b ) { return ( a > b )? 1 : -1; } );
array.sort( orderfunc )
比較関数orderfuncの順に並べ替えます。
比較関数には引数を2つ持たせます。この引数には比較対象となる配列の要素が渡されますが、渡される順番はブラウザによって異なります。この問題は1つの配列にsort()をくり返すときに、特に顕在化します。
ブラウザ | 第1引数 | 第2引数 |
---|---|---|
Internet Explorer | array[ 0 ] | array[ 1 ] |
Firefox | ||
Chrome | array[ 0 ] | array[ array.length / 2 ] |
比較関数は、戻り値として数値を返す必要があります。
戻り値 | 並べ替え方法 |
---|---|
0より小さな値 | 第1引数が第2引数の前になるように並べ替え |
0 | 並べ替えなし |
0より大きな値 | 第1引数が第2引数の後になるように並べ替え |
なお、配列の未定義の要素は必ず配列の最後になるように並べ替えられ、比較関数に渡されることはありません。
たとえば配列の要素が数値の場合、数値順に並べ替えるならば、
array.sort( function( a, b ) { return a - b; } );
のようにします。
比較関数 | 並べ替え方向 |
---|---|
function( a, b ) { return a - b; } |
昇順 |
function( a, b ) { return b - a; } |
降順 |
配列の要素がオブジェクトで、そのオブジェクトがdataというプロパティ名の数値を持つとします。この場合これを数値順に並べ替えるならば、
array.sort( function( a, b ) { return a.data - b.data; } );
のようにします。
array.reverse()
要素を逆順に並べ替えます。
1つの要素の順番を入れ替えるだけならば、次のようにsplice()で可能です。
var a = [ 0, 1, 2, 3, 4 ]; Sort(a, 3, 1); // 0, 3, 1, 2, 4 (3番目の要素を1番目へ移動) Sort(a, 1, 3); // 0, 2, 3, 1, 4 (1番目の要素を3番目へ移動) Sort(a, 2, 2); // 0, 1, 2, 3, 4 (2番目の要素を2番目へ移動) function Sort(a, target, dist) { var array = a.slice( 0 ); // 配列をコピー // target番目の要素を、distの位置へ移動 array.splice( dist, 0, array.splice( target, 1 )[ 0 ]); console.log( array ); }
array.concat( [value1[, value2[, ...[, valueN]]]] )Array.prototype.concat - JavaScript | MDN
このメソッドではarrayは変更されず、arrayにvalueを連結した新しい配列が返されます。valueを指定しないときには、arrayのコピーがそのまま返されます。
var a = [ 1, 2 ]; var b = [ 3, 4 ]; var c = a.concat( b ); // aは[1,2]のまま // cは[1,2,3,4]
引数の配列は要素に展開されますが、その要素に配列が含まれるときには、その配列までは展開されません。
a.concat( 3,[4,5],6 ); // [1,2,3,4,5,6]が返される a.concat( [3,4,[5,6]] ); // [1,2,3,4,[5,6]]
ちなみにpush()では、
var a = [ 1, 2 ]; var b = [ 3, 4 ]; var e = a.push( b ); // aが[1,2,[3,4]]となる // eは3 (aの要素数)
のように、配列はそのまま連結されます。
組み込みのメソッドとしては提供されないため、自前で処理する必要があります。
Array.filter()は、その配列の要素を引数としてテスト関数を呼び出します。そしてその関数がtrueを返す要素で、新しい配列を生成します。このときテスト関数では、Array.indexOf()の引数で渡された要素のインデックスを探索し、それが引数の要素のインデックスと合致するか判定します。
var array = [ 1, 'a', 2, 'a', 'あ', 'あ', 1 ]; var uniqueArray = array.filter( function( value, index, self ) { // 配列selfの要素valueの最初のインデックスと、indexが等しいならばtrueを返す return self.indexOf( value ) == index; }); alert( uniqueArray.join() ); // 1,a,2,あRemove Duplicates from JavaScript Array - Stack Overflow
オブジェクトに同名のプロパティを設定した場合、後に設定したもので先のそれを上書きします。この仕様を利用することで、重複したプロパティを持たないオブジェクトを作成できます。そしてこのオブジェクトのすべてのプロパティの値を配列にまとめることで、要素に重複のない配列を作成できます。
var array = [ 1, 'a', 2, 'a', 'あ', 'あ', 1 ]; var obj = {}; for( var i = 0; i < array.length; i++ ) { obj[ array[ i ] ] = array[ i ]; } // alert( JSON.stringify( obj ) ); // {"1":1,"2":2,"a":"a","あ":"あ"} var uniqueArray = []; for( var key in obj ) { uniqueArray.push( key ); } alert( uniqueArray.join() ); // 1,2,a,あRemove Duplicates from JavaScript Array - Stack Overflow
join()メソッドでは、配列の要素を文字列に変換して連結できます。よって、
var text = [ 'a', 'b', 'c' ].join( '' );
// abcが返される
のように文字列を作成できます。一方で、文字列を配列に分割するにはString.split()を使用します。
string = array.join( separator )Array.join - JavaScript | MDN
separatorを省略すると、「,」を指定したものとみなされます。
[1,2].join(); // "1,2"
連結時には文字列に変換されるため、論理値などもすべて文字列となります。
[true, false, null, '', Math].join(); // "true,false,,,[object Math]"
文字列へはtoString()で変換されるため、(0x10).toString()
が"16"を返すように、数値は10進数で出力されます。
[0x10, 10].join(); // "16,10"
要素が1つしかない場合にはseparatorは使用されず、その1つの要素が変換されただけの文字列が返されます。
[1].join('&'); // "1"
一方で要素が1つもなけらば、空文字列が返されます。
[].join('&'); // ""
配列を文字列に変換することで、配列のすべての要素を確認できます。これはtoString()を呼び出すことと同義であり、また得られる結果はjoin()で返される文字列と同じです。つまり次の4つの処理は、すべて同じ結果を得ます。
alert( array ); alert( array.toString() ); alert( array.join() ); alert( array.join( ',' ) );
このことからわかるように、join()の引数を変更することで一覧の形式を変更できます。たとえば改行文字 (\n
) 、もしくはbr要素で連結すると一覧が見やすくなります。
alert( array.join( '\n' ) );