配列(Array)は我々プログラマにとって馴染み深い要素のひとつです。配列はどんな入門書にも登場し、どんな高度なプログラムにおいても大活躍します。そしてJavaScritpに限らず、他の言語でも配列(あるいはリスト)は登場します。

こんなにも身近な配列ですが、「なんとなく」で使っていて「配列とはなんなのか」「何ができるのか」をあまり把握できていない方も多いと思います(もちろん私もそうです!)。

そこで、配列についてもう一度調べ上げ、情報をまとめてみることにしました。

JavaScriptにおけるArray

一般に配列(Array)とは、複数の値を管理するためのデータ構造です。JavaScriptにおいてもそれは同じで、Arrayは複数の値を持つことができます。

配列の作成

配列の作成には括弧を使ったリテラル記法か、new演算子を使います。

newで作成する方法は2通りあります。

引数が1つのときは配列のサイズを指定したことになり、そのサイズの配列が作成されます。2つ以上の引数を指定したときは配列の要素を指定したことになり、その要素をもつ配列が作成されます。

要素を全く持たない、空の配列を作成することもできます。

空要素を持つ配列

JavaScriptでは、要素が空である配列を作成することも可能です。

この場合、該当箇所が空となり、アクセスしようとしてもundefinedとなります。

また、newでサイズを指定して配列を作成した場合、全ての要素のデフォルト値は空です。

配列へのアクセス

配列の要素へのアクセスは括弧を使って行います。インデックス(配列の要素番号)を指定することにより、対応した番号の要素にアクセスできます。

インデックスは0から始まります。つまり、一番最初の要素は0番目になります。これは歴史的な理由によります。

存在しないインデックスにアクセスするとundefinedとなります。

また、推奨はしませんが、文字列キーによるアクセスも可能です。

配列への値の代入も同様に行えます。

可変長

JavaScriptの配列は全て可変長です。つまり配列のサイズは固定ではないということです。

配列の長さはlengthプロパティにより調べることができます。

lengthプロパティに値をセットすることで、配列のサイズを変更できます。

配列を伸ばしたとき、新たな領域には何も値が入らず、空になります。また、配列を短くしたとき、はみ出てしまった要素は削除されます。

lengthプロパティの変更だけでなく、一部のメソッドでも長さが変わります。例えば配列の後ろに値を追加するpushメソッドなどがあります。

オブジェクト型

JavaScriptの型はプリミティブ型(文字列、数値など)とオブジェクト型(Objectなど)に大別できますが、配列はオブジェクト型になります。

オブジェクト型なので、配列自体の値は参照値として扱われることに注意が必要です。詳しくは「JavaScriptの変数と配列と参照について」をご覧ください。

また、配列はオブジェクトであるため、常にtruthy(trueとして扱われる)です。空配列もtrue扱いになります。

配列に入る値

配列に入る値の型に制限はありません。数値、文字列、オブジェクト、なんでも可能です。

配列の中に配列を含めることも可能です。これは行列などを表現する際に便利です。

また、配列の中に複数の型を混在させることも可能です。

スプレッド演算子

スプレッド演算子(…)を使用して、配列の値を展開することが可能です。

展開した配列は、他の配列の要素として展開したり、関数呼び出しの引数として扱うことが可能です。

分割代入

配列のそれぞれの値を別々の変数に代入する、分割代入という機能があります。

分割代入には様々なバリエーションがあります。

Iterable

配列は@@iteratorメソッドを実装しており、反復処理が可能なIterableです。@@iteratorシンボルは定数Symbol.iterableで取得できます。

イテレータについて詳しくは「JavaScriptのIteratorとGeneratorを使って反復処理を書く」をご覧ください。

より簡易なイテレータの処理方法として、for-ofがあります。通常はこちらを使います。

配列のメソッド

Array.from(arrayLike, mapFn = undefined, thisArg = undefined)

Array.fromはstaticなメソッドで、配列っぽいもの(array-like)およびiterableオブジェクトから新しい配列を作成します。配列のコピーなどに使用できます。

このとき、コピーは浅いコピー(シャローコピー)となり、中のオブジェクト自体は複製されません。あくまでも配列のコピーとなります。

ちなみにスプレッド演算子を使用しても同様のことが実現できます。

Array.fromが受け付けるのは配列だけでなく、配列っぽいもの(array-like)とiterableなので、例えばNodeListを配列に変換することなども可能です。

Array.fromでは、第二引数に関数を入れることで、変換時にmapメソッドを同時にかけることもできます。

また、第三引数ではmap関数内で使用するthisの値を指定することができます。

Array.isArray(obj)

Array.isArrayは、引数の値が配列かどうかをチェックすることができます。配列ならばtrueを返し、そうでなければfalseを返します。

Array.of(element1, element2, …elementN)

Array.ofは引数に与えられた値を持った配列を作成します。newえ配列を作成するときとほぼ同じです。異なるのは、引数がひとつのときの挙動で、Array.ofは引数がひとつでも、その要素を持った配列を作成します。

concat(other)

concatは配列同士を結合し、新しい配列を生成するメソッドです。このメソッドは元の配列および引数に与えた配列を変更せず、ただ新しい配列を返します。

結合には浅いコピー(シャローコピー)が使われます。

copyWithin(target, start = 0, end = this.length)

copyWithinメソッドは、配列内の一部を、配列内の別の場所にコピーして上書きします。戻り値は配列自身です。

第一引数にコピー先を指定し、第二引数にコピー元の開始地点、第三引数にコピー元の終了地点を指定します。デフォルトでは配列の先頭から末尾までの全てがコピー元になります。範囲はstartを含み、endを含みません。

引数にマイナスの値を指定すると、末尾からの位置になります。

コピー時にはみ出た値は破棄されます。

entries()

entriesメソッドは[key, value]ペアを扱うiteratorを返します。

for-ofと分割代入を活用すると、key-valueペアを簡単に分離できます。

every(testFunc, thisArg = undefined)

everyメソッドはテスト関数を受け取り、配列の要素全てがテスト関数を通過した時にtrueを返し、ひとつでもテストに落ちればfalseを返すメソッドです。

テスト関数は配列の値をひとつ受け取り、trueかfalseを返す関数です。

また、第二引数で、テスト関数内で使用するthisの値を指定することも可能です。

テスト関数は最大3つの引数を取ります。第2引数は現在の値のインデックスで、第3引数は対象の配列そのものです。

fill(value, start = 0, end = this.length)

fillメソッドは配列のstartからendまでのインデックスの値をvalueにします。このときendは含まれません。

startかendにマイナスの値を指定すると、配列の末尾からのインデックスになります。

newで作成した空配列の値を埋めるのにも便利です。

filter(testFunc, thisArg = undefined)

fileterメソッドはテスト関数をtrueで通過した要素のみを新たな要素とする、新たな配列を返します。元の配列は変更しません。

テスト関数は引数を1つから3つ受け取る関数で、trueかfalseを返します。つまりeveryメソッドのテスト関数と同じです。第1引数に値を、第2引数に値のインデックスを、第3引数に配列そのものを受け取ります。

テスト関数を通してtrueになった要素のみが、新たな配列の要素になります。

filterメソッドの第2引数には、テスト関数のthisとして使う値を指定できます。

find(testFunc, thisArg = undefined)

findメソッドはテスト関数がtrueになる最初の要素を返します。見つからない場合はundefinedを返します。

findメソッドの第2引数にはテスト関数で使うthisの値を指定できます。

findIndex(testFunc, thisArg = undefined)

findIndexメソッドはfindメソッドとほぼ同じですが、こちらは配列の値ではなくインデックスを返します。

第2引数にはテスト関数で使うthisの値を指定できます。

flat(depth = 1)

flatメソッドは配列内の配列を展開して、新しい配列を返します。depthには何段階まで展開するかの深さをしてできます。元の配列は変更しません。

このメソッドは現在Chrome69のみ対応しています。

flatMap(mapFunc, thisArg = undefined)

flatMapメソッドは配列の要素にmapFunc関数を適用した後、その結果を配列内に展開します。

mapFunc関数は最大3つの引数を取ります。

このメソッドは現在Chrome69のみ対応しています。

forEach(callback, thisArg = undefined)

forEachメソッドは配列の各要素に対して順番にcallback関数を適用します。戻り値はありません。

for文やfor-ofの代替として使用することができます。

ただしforEachメソッドはforやfor-ofと比べると著しく遅く、巨大な配列に対して使用すべきではありません。

includes(searchElement, fromIndex = 0)

includesメソッドは配列にsearchElementが含まれている場合はtrueを、そうでない場合はfalseを返します。fromIndexには検索開始位置を指定できます。負の値を与えた場合は、末尾からのインデックスになります。

indexOf(searchElement, fromIndex = 0)

indexOfメソッドは配列のsearchElementのインデックスを返します。存在しない場合は-1を返します。fromIndexには検索開始位置を指定できます。負の値を与えた場合は、末尾からのインデックスになります。

要素の比較には、厳密な比較(===)が使用されます。

join(separator = ‘,’)

joinメソッドは、配列の全ての要素をカンマで繋いだ文字列を返します。separatorを指定することでカンマ以外の区切り文字も使えます。区切り文字を使いたくない場合は、空文字列を渡します。

keys()

keysメソッドは配列のキーを扱うiteratorを返します。配列のキーとは、つまりインデックスのことです。entriesメソッドのキーのみ版と言えます。

lastIndexOf(searchElement, fromIndex = this.length – 1)

lastIndexOfは配列を末尾から検索し、searchElementのあるインデックスを返します。見つからない場合は-1を返します。fromIndexを指定すると、fromIndexから逆向きに検索していきます。

要素の比較には厳密な比較(===)が使用されます。

map(mapFunc, thisArg = undefined)

mapメソッドは、配列の各要素に対してmapFunc関数を適用し、その結果をまとめた配列を新しい配列として返します。元の配列は変更されません。

pop()

popメソッドは配列の最後の要素を取り出して返し、配列から削除します。配列が空の場合はundefinedを返します。

push(element1, element2, …elementN)

pushメソッドは配列の末尾に新しくelementを追加し、要素を追加後のlengthを返します。

このメソッドはスプレッド演算子による配列の展開とも相性が良く、別の配列の値を個別にpushすることもできます。

reduce(callback, initialValue = this[0])

reduceメソッドは、配列の値に対してinitialValueを初期値として、左から右に次々とcallback関数を適用していき、ひとつの値にまとめて返します。元の配列は変更されません。

initialValueが指定されたときは、initialValueを初期値として、最初の要素から処理が開始されます。initialValueに初期値を指定しないときは、配列の最初の値をinitialValueとして、2番目の要素から処理を開始します。

この複雑なメソッドを理解するための第一歩は「配列の総和」です。配列の各要素を次々と足していき、総和を求めます。

このときcallback関数は2つの引数を取ります。ひとつめはprevで、callback関数が前の実行時に返した値がここに入ります。まだ初めの実行のときは、initialvalueが入ります。

ふたつめはcurrentで、配列の左から順番に、現在の値が入ります。今回はinitialValueが未指定なので、2番目の要素(つまり「10」)から始まります。

このとき「10」に対してcallback関数を実行し、prev + currentで、5 + 10を計算して「15」を返しています。この「15」が次のcallback実行時のprevになります。

次に3番目の要素「20」に対してcallback関数を実行し、prevは「15」でcurrentは「20」です。ここでprev + currentを返すので、「35」です。これで配列の最後まで行ったのでこれを最終結果とし、このメソッドの戻り値は「35」となります。

また、initialValueを指定すれば、その値をベースに計算ができます。

initialValueやcallback関数の戻り値は数値である必要はなく、オブジェクトなどでも実行可能です。

また、callback関数は最大4つまでの引数を取ります。

reduceRight(callback, initialValue = this[this.length – 1])

reduceRightメソッドは右から左に向けてreduceします。使い方はreduceメソッドと同じです。

reverse()

reverseメソッドは配列を反転させ、反転させた配列を返します。このメソッドは元の配列を変更します。

shift()

shiftメソッドは配列から最初の値を取り出し、返します。popメソッドは最後の値を取り出しましたが、shiftメソッドは最初の値を取り出します。配列が空の場合はundefinedを返します。

slice(begin = 0, end = this.length)

sliceメソッドは配列の一部(beginからendまで)を切り出し、新しい配列として返します。endの値は含めず、endの直前までを切り出します。

startおよびendにマイナスの値を指定すると、配列の最後からのインデックスとして扱われます。

some(testFunc, thisArg = undefined)

someメソッドは配列の要素の最低ひとつでもテスト関数に合格するならtrueを、ひとつも合格しないならfalseを返します。テスト関数はtrueかfalseを返す関数です。

このメソッドはeveryメソッドと似ていますが、everyメソッドは全ての要素が合格しないといけないのに対し、someメソッドはひとつでも合格すればtrueになります。

testFunc関数は最大3つの引数を取ります。

また、余談ですが、このsomeメソッドを配列のイテレーションに使うことを推奨する劣悪な資料がネット上にはあります。someメソッドはあくまでも配列の要素がテスト関数を満たすかどうかをチェックするためのメソッドであり、イテレーションのためのメソッドではありません。単純なイテレーションの場合はfor、for-of、forEachメソッドなどを使用してください。

sort(compareFunc = undefined)

配列を文字列の辞書順でソートし、ソートした配列を返します。このメソッドは元の配列を変更します。

compareFuncに任意の比較関数を渡すことで、ソートの挙動を変更できます。compareFuncは負数、0、正の数のいずれかを返します。

  • comapreFunc(a, b)が負数(-1など)を返した場合、aはbより先に来ます
  • compareFunc(a, b)が0を返した場合、aとbは同じ値です
  • compareFunc(a, b)が正の数(1など)を返した場合、bがaより先に来ます

単純な数値順ソートをしたい場合、a – bまたはb – aを計算する関数を渡せば実現できます。

compareFuncを指定しない場合は、辞書順ソートとなるため、たとえば「70」は「8」より前に来ます。

splice(index, howMany, element1 = undefined, …elementN = undefined)

spliceメソッドは、配列の中から要素を取り除きます。また、取り除いた後に要素を付け加えることも可能です。このメソッドは元の配列を変更します。

Arrayには「remove」のようなメソッドがないため、特定要素を取り除くためにもspliceはよく使用されます。

toLocaleString()

toLocaleStringメソッドは配列をロケール固有の文字列に変換して返します。

例えば日本ならば数字にカンマがついたりします。

内部処理としては、各要素のtoLocaleStringメソッドを呼び出しています。

toString()

toStringメソッドは配列を文字列に変換して返します。

配列の各要素をカンマで繋いで返します。

unshift(element1, element2, …elementN)

unshiftメソッドは配列の最初に要素を追加し、追加後の配列の長さを返します。このメソッドは元の配列を変更します。

values()

valuesメソッドは配列の各値を扱うiteratorを返します。