JavaScript入門 コレクション
コレクションは、値をまとまりで管理するオブジェクトのことです。JavaScriptで使えるコレクションは、ES5まではObjectとArrayのみでしたが、ES6からMap,Set,WeakMap、WeakSetも使えるようになりました。
配列(Array)
オブジェクトの場合はプロパティと値を対で格納しますが、配列の場合は値のみを格納します。格納された値はそれぞれ、値に対応したインデックスが0から順に振られます。
配列の初期化
配列は、リテラル表記またはArrayを使って初期化(インスタンス化)できます。
配列の初期化(リテラル表記)
配列リテラル([ ])を記述することで配列を初期化できます。
構文:リテラルを使った配列の初期化
const 配列 = [ 値1, 値2, 値3, ・・・ ];
[ ]を使うことで、配列を宣言できます。また、[ ]の中にカンマ(,)区切りで渡された値は、配列の初期値として設定されます。空の配列を生成したい場合には、値を省略して[ ]のみで宣言することもできます。
リテラルで配列を初期化する例
const fruits = [ "banana", "orange", "grape" ];
console.log( fruits );
配列の初期化(new Array)
new Arrayを記述して配列を初期化することもできます。
構文:Arrayを使った配列の初期化
引数が1つの場合
const 配列 = new Array( 配列の長さ );
引数が2つ以上の場合
const 配列 = new Array( 値1, 値2, ・・・ );
new Arrayに数値を1つ渡した場合には、その値に一致する長さの空の配列が生成されます。一方、new Arrayに複数個の引数を渡した場合には、その値を含む配列が生成されます。
new Arrayで配列を初期化する例
const emptyArry = new Array( 3 );
console.log( emptyArry );
const filledArry = new Array( 1, 2, 3 );
console.log( filledArry );
配列の基本操作
生成した配列の特定の値を取得・変更したい場合には、インデックスを使います。
const fruits = [ "banana", "orange", "grape" ];
console.log( fruits[0] ); //0番目の要素の取得
fruits[ 1 ] = "apple"; //1番目の要素("orange")の変更
console.log( fruits );
配列の長さを取得
配列の長さ(個数)は、lengthプロパティから取得できます。
const fruits = [ "banana", "orange", "grape" ];
console.log( fruits.length );
>3
配列のlength -1のインデックスが配列の最後の要素のインデックスになります。
const fruits = [ "banana", "orange", "grape" ];
console.log( fruits[fruits.length - 1] );
>grape
配列にはすべての型の値を格納できるため、配列の中に他の配列やオブジェクトを設定することもできます。他階層の配列から2階層目以降の要素を取得するときには、[ 1階層目 ][ 2階層目 ]のようにブラケットつなげて記述できます。
const array2D = [
[ "太郎" , "25歳", "男" ], //配列の格納
{ name: "花子", age: "23歳" , gender: "女" } //オブジェクトの格納
];
console.log( array2D[0] );
>[ "太郎" , "25歳", "男" ] //0番目に登録されている配列が取得される
console.log( array2D[0][0] ); //[ 1階層目 ][ 2階層目 ]
>太郎
console.log( array2D[0][2] );
>男
console.log( array2D[1].name ); //ドット記法でプロパティを取得
>花子
console.log( array2D[1][ "age" ] ); //ブラケット記法でプロパティを取得
>23歳
配列のメソッド
配列には、様々なメソッドが用意されています。メソッドを使うことで、宣言したあとでも値の取得・変更・削除など行うことができます。
配列に要素を追加
pushメソッド:末尾に追加
pushメソッドは、配列の末尾に要素を追加します。
構文:push記法
配列.push( 追加したい要素1[, 追加したい要素2, ・・・] );
使用例
const fruits = [ "banana", "orange", "grape" ];
fruits.push( "apple" ); //配列の末尾に要素を追加
console.log( fruits );
> [ "banana", "orange", "grape", "apple" ] //末尾に"apple"が追加されている
unshift:先頭に追加
unshiftメソッドは、配列の先頭に要素を追加します。
構文:unshift記法
配列.unshift( 追加したい要素1[, 追加したい要素2, ・・・] );
使用例
const fruits = [ "banana", "orange", "grape" ];
fruits.unshift( "lemon" ); //配列の先頭に要素を追加
console.log( fruits );
> [ "lemon" , "banana", "orange", "grape" ] //先頭に"lemon"が追加されている
配列から要素を削除
配列から要素を削除するときに使うメソッドです
shift:先頭を削除
shiftメソッドは、配列の先頭の要素を削除します。
構文:shiftの記法
let 削除した要素 = 配列.shift();
使用例
const fruits = [ "banana", "orange", "grape" ];
let returnVal = fruits.shift(); //配列の先頭に要素を削除
console.log( fruits );
> [ "orange", "grape" ] //先頭に"banana"が削除されている
console.log( returnVal );
>"banana" //配列から削除された要素が戻り値となる
pop:末尾を削除
popメソッドは、配列の末尾の要素を削除します。
構文:popの記法
let 削除した要素 = 配列.pop();
使用例
const fruits = [ "banana", "orange", "grape" ];
let returnVal = fruits.pop(); //配列の末尾に要素を削除
console.log( fruits );
> [ "orange", "grape" ] //末尾に"grape"が削除されている
console.log( returnVal );
>"grape" //配列から削除された要素が戻り値となる
splice:要素の切り取り
spliceメソッドは、開始位置から特定の長さ分を切り取ります。spliceは、特定の要素を切り取ります。このとき、元になる配列から要素が削除されます。元の配列を維持する場合は、sliceメソッドを使用します。
構文:spliceの記法
let 切り取られた配列 = 元の配列.splice( 開始位置, 長さ [,要素追加1, 要素追加2, ・・・ ] );
使用例
const fruits = [ "banana", "orange", "grape" ];
let deleteVal= fruits.splice(1,2); //インデックス1から長さ2つ分切り取り
console.log( fruits );
> [ "banana" ] //元の配列から要素が切り取られる
console.log( deleteVal );
>"orange", "grape" //切り取られた配列
spliceでは、第3引数以下の要素を、要素を削除した箇所に追加できます。
const fruits = [ "banana", "orange", "grape" ];
fruits.splice(1,1, "apple", "lemon" ); //"orange"を削除し、"apple", "lemon"を追加
console.log( fruits );
>[ "banana", "apple", "lemon", "grape" ]
配列の結合・複製
配列の結合や複製(コピー)を行う場合には、concatメソッドを使います。また、特定の要素を複製したい場合には、sliceメソッドを使います。
concat:配列の結合
concatメソッドを使うと、別の配列を結合した新しい配列を作成します。
構文:concatの記法
let 結合された配列 = 配列1.concat(配列2);
使用例
const fruits = [ "banana", "orange", "grape" ];
const newFruits = fruits.concat( [ "melon" , "mango" ] ); //配列を結合
console.log( newFruits );
> [ "banana", "orange", "grape","melon" , "mango" ] //"melon" , "mango"が末尾に追加される
console.log( fruits );
> [ "banana", "orange", "grape" ] //元の配列は変更されない
concat:配列の複製
concatメソッドを使うと、同じ要素を持つ新しい配列を作成(複製)します。
構文:concatの記法
let 配列を複製した配列 = 配列1.concat();
使用例
const fruits = [ "banana", "orange", "grape" ];
const newFruits = fruits.concat(); //引数を省略すると要素が同じ新しい配列が作成される
console.log( newFruits );
> [ "banana", "orange", "grape" ] //fruitsと同じ要素を持つ新しい配列
ES6以降では、配列の結合や複製は、スプレット演算子を使うのが主流です。
slice:特定の要素を抽出した新しい配列の作成
sliceメソッドは、開始位置から終了位置の直前の要素までを抽出した新しい配列を返します。また、spliceと違い、元の配列に対して影響を及びしません。
構文:sliceの記法
let 切り取られた配列 = 元の配列.slice( 開始位置,終了位置);
使用例
const fruits = [ "banana", "orange", "grape" ];
const newFruits = fruits.slice(1,2); //インデックス1からインスタンス2の直前の要素までを抽出
console.log( newFruits );
> [ "orange" ] //終了位置の要素(grape)は含んでいない
console.log( fruits );
>[ "banana", "orange", "grape" ] //元の配列に影響はない
const toEndFruits = fruits.slice( 1 ); //終了位置を指定しない場合、開始位置からすべての要素が複製される
console.log( toEndFruits );
>[ "orange", "grape" ] //インデックス1以降の要素を持つ新しい配列
const allFruits = fruits.slice(); //開始位置及び終了位置を指定しない場合、すべての要素が複製される
console.log( allFruits );
>[ "banana", "orange", "grape" ] //fruitsと同じ要素を持つ新しい配列
シャローコピーとディープコピーについて
シャローコピーとディープコピーは、主に非プリミティブ型の値(オブジェクトや配列など)に対して使われる用語です。シャローコピーは参照(アドレス)のコピー、ディープコピーはオブジェクト自体のコピーを指します。
シャローコピー
シャローコピーは、浅いコピーです。シャローコピーの場合には、オブジェクトのアドレスをコピーします。そのため、オブジェクトの要素はコピーされません。
配列オブジェクトのシャローコピー
const original = [ "元の値" ];
const copied = original; //アドレスをコピー
copied[ 0 ] = "変更後の値"; //アドレスをコピー
console.log( original[ 0 ] );
>変更後の値 //元のオブジェクトの値が変わる
シャローコピーの場合には、変数copiedに格納されるのは変数originalが保持していた配列オブジェクトへの参照です。そのため、copiedの要素の値を変更すると、元の配列(original)の値も変更されます。
ディープコピー
ディープコピーは、深いコピーです。ディープコピーの場合には、配列オブジェクトの保持する値も複製して、別の配列オブジェクトを新たに作成します。
配列オブジェクトのディープコピー
const original = [ "元の値" ];
const copied = original.concat(); //同じ要素を保持する配列を新しく作成
copied[ 0 ] = "変更後の値";
console.log( original[ 0 ] );
>元の値 //元のオブジェクトの値はかわらない
concatメソッドやsliceメソッドでディープコピーを行った場合には、1階層目のみディープコピーが行われます。オブジェクトが多階層の構造になっている場合には、2階層以降はディープコピーされない。
配列が多階層の場合
const original = [
"1階層目の値",
[ "2階層目の値" ]
];
const copied = original.concat(); //同じ要素を保持する配列を新しく作成
copid[ 0 ] = "変更後の値"; //1階層目の値を変更
copid[ 1 ][ 0 ] = "変更後の値"; //2階層目の値を変更
console.log( original[ 0 ] );
>1階層目の値 //1階層目はoriginalには影響なし
console.log( original[ 1 ][ 0 ] );
>変更後の値 //2階層目はoriginalの値も変わる
そのため、concatやsliceでの配列の複製は、配列の完全ディープコピーではありません。
配列内の要素の存在チェック
配列内に特定の要素が格納されているかを確認したい場合があります。そのようなときは、次の方法で配列内の要素の存在確認を行います。
indexOf:最初に一致したインデックスを返す
indexOfメソッドは、配列内で最初に一致した要素のインデックスを返します。
構文:indexOfの記法
let 一致したインデックス = 配列.indexOf(存在確認したい値);
使用例
const fruits = [ "banana", "orange", "grape" ];
const found = fruits.indexOf( "grape" );
console.log( found );
>2 //"grape"はインデックス2の要素に一致
const notFound = fruits.indexOf( "watermelon" );
console.log( notFound );
>-1 //要素が見つからない場合には-1が返る
includes:値が存在するか確認
includesメソッドは、配列内の要素に値が存在するかを確認します。
構文:includesの記法
let 真偽値 = 配列.includes(存在確認したい値);
使用例
const fruits = [ "banana", "orange", "grape" ];
const found = fruits.includes( "grape" );
console.log( found );
>true //一致するものが見つかった
const notFound = fruits.includes( "lemon" );
console.log( notFound );
>false //一致するものが見つからない
その他のメソッド
join:要素を結合して文字列を作成
joinメソッドは、配列の要素を結合して文字列を作成します。
構文:joinの記法
let 結合された文字列 = 配列.join( [ 区切り文字 ] );
区切り文字:要素を結合する際の区切り文字を設定します。省略したときにはカンマ(,)で結合されます。
使用例
const arry = [ "Hello", "World" ];
console.log( arry.join( " " ) ); //スペースで結合
>Hello World
fill:要素を特定の値で埋める
fillメソッドは、配列の開始位置、終了位置で範囲指定したインデックスの要素に対して、特定の値を設定します。開始位置、終了位置を省略した場合には、すべての要素を指定した値で上書きします。
構文:fillの記法
配列.fill( 各要素に設定したい値 [, 開始位置, 終了位置] );
たとえば、要素数が大きい配列に対して初期値を設定したい場合などに簡単に記述できます。
長さ100の配列に初期値0を設定したい場合
//fillを使わない場合
const arry1 = [];
for( let i = 0; i < 100; i++ ){
arry1.push( 0 ); //pushで1つずつ末尾に0を追加
}
console.log( arry1 );
>[ 0, 0, 0, 0,・・・ ] //長さ100、初期値0の配列
//fillを使った場合
const arry2 = new Array( 100 ); //長さが100の空の配列を作成
arry2.fill( 0 ); //すべての要素に0を設定
//上の2行を次のように書くとより簡略化できます。
//( new Array( 100 ) ).fill( 0 )
console.log( arry2 );
>[ 0, 0, 0, 0,・・・ ] //長さ100、初期値0の配列
flat:多次元配列の平坦化(次元を減らす)
flatメソッドは、多次元配列を引数(平坦化レベル)で指定した次元分、配列の構造を平坦化します。なお、引数を指定しない場合には、1次元分、平坦化します。多次元配列とは、配列構造が他階層で形成されている配列のことです。配列の次元を調整するときに使いましょう。
構文:flatの記法
let 平坦化された配列 = 多次元配列.flat([ 平坦化レベル ]);
const arry3D = [ //配列の中に配列が存在する
1, [ 2 ], 3,
[ 4, [ 5 ] ]
];
const arry2D = arry3D.flat(); //1次元分、平坦化を行った配列を返す
console.log( arry2D );
>[1, 2, 3, 4, [5]]
const arry1D = arry3D.flat( 2 );//2次元分、平坦化を行った配列を返す
console.log( arry1D );
>[1, 2, 3, 4, 5]
reverse:要素の順番を逆に置換
reverseメソッドは、配列の要素の並びを逆にします。
構文:flatの記法
配列.reverse();
const arry = [1, 2, 3, 4, 5];
arry.reverse();
console.log( arry);
>[5, 4, 3, 2, 1]