原文: JavaScript Array of Objects Tutorial – How to Create, Update, and Loop Through Objects Using JS Array Methods

筆者は毎週だいたい 18 回くらいは JSON データを扱うことがあると思います。それでもまだ、目的に合わせてデータを操作する方法をほぼ毎回 Google で検索しています。その答えが常に見つかるような究極のガイドがあれば良いと思いませんか?

この記事では、JavaScript でオブジェクトの配列を操作するための基本を紹介します。

JSON 形式のデータを使用したことがあれば、JavaScript オブジェクトを使用したことがあると言えるでしょう。JSON とは JavaScript Object Notation の略です。

オブジェクトの作成はとてもシンプルです。次のように書くだけです。

{
  "color": "purple",
  "type": "minivan",
  "registration": new Date('2012-02-03'),
  "capacity": 7
}

上記のオブジェクトは車を表現しています。車にはさまざまな種類や色があり、各オブジェクトは特定の車を表します。

purple

さて、多くの場合、このようなデータを外部のサービスから取得します。しかし、オブジェクトとその配列を自身で作成することもあるでしょう。筆者がこのオンラインショップを作成した時もそうでした。

categories

このカテゴリー一覧の各アイテムが、HTML で書くと下記のようになっていると考えてみてください。

code

このコードを 12 回繰り返して書きたくはありませんでした。メンテナンスが困難になるからです。

オブジェクトの配列を作成する

では車の例に戻りましょう。この車のセットを見てください。

cars

これは、次のように配列で表現することができます。

let cars = [
  {
    "color": "purple",
    "type": "minivan",
    "registration": new Date('2017-01-03'),
    "capacity": 7
  },
  {
    "color": "red",
    "type": "station wagon",
    "registration": new Date('2018-03-03'),
    "capacity": 5
  },
  {
    ...
  },
  ...
]

オブジェクトの配列は、ずっと同じ状態とは限りません。ほとんどの場合、何かしらの操作をする必要が出てきます。では、既存の配列にオブジェクトを追加する方法を見てみましょう。

オブジェクトを最初に追加する - Array.unshift

beginning

配列の最初の位置にオブジェクトを追加するには、Array.unshift を使用します。

let car = {
  "color": "red",
  "type": "cabrio",
  "registration": new Date('2016-05-02'),
  "capacity": 2
}
cars.unshift(car);

オブジェクトを最後に追加する - Array.push

ending

配列の最後の位置にオブジェクトを追加するには、Array.push を使用します。

let car = {
 "color": "red",
 "type": "cabrio",
 "registration": new Date('2016-05-02'),
 "capacity": 2
}
cars.push(car);

オブジェクトを途中に追加する - Array.splice

middle

配列の途中の位置にオブジェクトを追加するには、Array.splice を使用します。この関数はアイテムを取り除くこともできるため、とても便利です。引数の取り方には少し注意が必要かもしれません。

Array.splice(
  {変更の開始位置のインデックス},
  {取り除くアイテムの数},
  {追加するアイテム}
);

したがって、赤いフォルクスワーゲンのカブリオ (Cabrio、オープンカー) を 5 番目の位置に追加したい場合には、次のようになります。

let car = {
  "color": "red",
  "type": "cabrio",
  "registration": new Date('2016-05-02'),
  "capacity": 2
}
cars.splice(4, 0, car);

オブジェクトの配列をループして操作する

ここで質問があります。あなたはなぜオブジェクトの配列をループしたいのでしょうか?

なぜそのようなことを聞くかというと、ループすること自体が最終的に達成したい目的であることはほとんどないからです。

JavaScript では、ループを使って自分でロジックを実装しなくても問題を解決できるように多くの関数が用意されています。では見ていきましょう。

配列内のオブジェクトを値で検索する - Array.find

例として、赤い車を見つけたいとしましょう。そのためには Array.find という関数を使うことができます。

cars-colorred
let car = cars.find(car => car.color === "red");

この関数は最初に一致した要素を 1 つ返します。

console.log(car);
// 出力:
// {
//   color: 'red',
//   type: 'station wagon',
//   registration: 'Sat Mar 03 2018 01:00:00 GMT+0100 (GMT+01:00)',
//   capacity: 5
// }

また、複数の値を条件にして検索することもできます。

let car = cars.find(car => car.color === "red" && car.type === "cabrio");

この例では配列内の最後の車が取得されます。

配列から条件に当てはまる複数のオブジェクトを取得する - Array.filter

Array.find 関数はオブジェクトを 1 つだけ返す関数でした。赤い車をすべて取得したい場合には Array.filter を使う必要があります。

cars-colorred2
let redCars = cars.filter(car => car.color === "red");
console.log(redCars);
// 出力:
// [
//   {
//     color: 'red',
//     type: 'station wagon',
//     registration: 'Sat Mar 03 2018 01:00:00 GMT+0100 (GMT+01:00)',
//     capacity: 5
//   },
//   {
//     color: 'red',
//     type: 'cabrio',
//     registration: 'Sat Mar 03 2012 01:00:00 GMT+0100 (GMT+01:00)',
//     capacity: 2
//   }
// ]

配列内のオブジェクトを変換する - Array.map

これはよく必要になる操作です。あるオブジェクトの配列を異なるオブジェクトの配列へと変換します。これは Array.map の役割です。では、車をサイズに基づいて 3 つのグループに分類する例を考えましょう。

cars-sizes
let sizes = cars.map(car => {
  if (car.capacity <= 3){
    return "small";
  }
  if (car.capacity <= 5){
    return "medium";
  }
  return "large";
});
console.log(sizes);
// 出力:
// ['large','medium','medium', ..., 'small']

サイズ以外の値も必要であれば、新しいオブジェクトを作成することも可能です。

let carsProperties = cars.map(car => {
 let properties = {
   "capacity": car.capacity,
   "size": "large"
 };
 if (car.capacity <= 5){
   properties['size'] = "medium";
 }
 if (car.capacity <= 3){
   properties['size'] = "small";
 }
 return properties;
});
console.log(carsProperties);
// 出力:
// [
//   { capacity: 7, size: 'large' },
//   { capacity: 5, size: 'medium' },
//   { capacity: 5, size: 'medium' },
//   { capacity: 2, size: 'small' },
//   ...
// ]

配列内の全オブジェクトにプロパティを追加する - Array.forEach

では、車にサイズの情報を追加したい場合はどうしますか?その場合、元のオブジェクトに新しいプロパティ size を追加して拡張できます。これは Array.forEach 関数が役に立つ場面です。

cars.forEach(car => {
 car['size'] = "large";
 if (car.capacity <= 5){
   car['size'] = "medium";
 }
 if (car.capacity <= 3){
   car['size'] = "small";
 }
});

配列をプロパティでソートする - Array.sort

オブジェクトの変換が完了したら、次はオブジェクトを何らかの方法で並べ替えたいことがよくあります。

ソートは通常、すべてのオブジェクトが持っているプロパティの値に基づいて行います。ソートには Array.sort 関数が使用できますが、並べ替えのメカニズムを定義する関数を用意する必要があります。

例えば車を定員 (capacity) に基づいて降順に並べ替えたいとしましょう。

cars-sort
let sortedCars = cars.sort((c1, c2) => (c1.capacity < c2.capacity) ? 1 : (c1.capacity > c2.capacity) ? -1 : 0);
console.log(sortedCars);
// 出力:
// [
//   {
//     color: 'purple',
//     type: 'minivan',
//     registration: 'Wed Feb 01 2017 00:00:00 GMT+0100 (GMT+01:00)',
//     capacity: 7
//   },
//   {
//     color: 'red',
//     type: 'station wagon',
//     registration: 'Sat Mar 03 2018 01:00:00 GMT+0100 (GMT+01:00)',
//     capacity: 5
//   },
//   ...
// ]

Array.sort は、2 つのオブジェクトを比較し、もし並べ替え用の関数の実行結果が正の数であれば、1 番目のオブジェクトを 2 番目の位置に動かします。つまり、並べ替え用の関数は「1 番目のオブジェクトを 2 番目に配置すべきですか?」という質問だと考えることができます。

sort

不要な位置交換を避けるために、両方のオブジェクトの値が同じだった場合を示す 0 (ゼロ) のケースを加えることを忘れないでください。

配列内のオブジェクトが条件を満たすかチェックする - Array.every, Array.some

Array.everyArray.some は、各オブジェクトが特定の条件を満たすかのチェックだけを行いたい場合に便利です。

例えば、配列内に赤いカブリオがあるでしょうか?すべての車に最低 4 人が乗車できるでしょうか?もっとウェブに関連した例で言うと、ショッピングカート内に特定の製品があるでしょうか?

cars.some(car => car.color === "red" && car.type === "cabrio");
// 出力: true

cars.every(car => car.capacity >= 4);
// 出力: false

もしかしたら、Array.some によく似た関数の Array.includes を覚えているかもしれません。しかし、Array.includes はプリミティブ型の配列でのみ動作します。

まとめ

この記事では、オブジェクトの配列を作成、操作、変換、ループする基本的な関数について説明しました。つまずきがちなケースのほとんどをカバーしているはずです。

より高度な機能を必要とするユースケースがあれば、こちらの配列についての詳細なガイド (英語)W3Schools のリファレンス (英語) を参照してください。

または筆者にご連絡ください。また別の記事を用意します :-)