オブジェクトの配列について
データを展開する前に、まずは今回取り扱うデータであるオブジェクトの配列の構造(中身)について、確認していきましょう。
JavaScriptでは配列やオブジェクトといった形式で複数のデータを扱うことが多いです。
シンプルなものを例にすると、配列とオブジェクトはそれぞれ下のように書かれます。
JavaScript
// 配列
const arr = [ 0,1,2,3 ];
// オブジェクト
const obj = {
id: 1,
name: "佐藤",
mail: "xxx@xxx.xxx"
}
配列ではデータに番号(インデックス)が与えられるので、データのソートや追加・削除が容易というメリットがある一方、種類が異なるデータ(id番号と名前など)を一度にまとめるのには向いていません。
シンプルな配列で種類が異なるデータをまとめてしまうと、下のようにとても見づらく、管理しづらいコードになってしまいます。
JavaScript
// 配列
const arr = [ 1,"佐藤","xxx@xxx.xxx",2,"鈴木","yyy@yyy.yyy" ];
一方、種類が異なるデータはオブジェクトとして管理すると分かりやすくて便利なのですが、一つのオブジェクトデータだけでは配列のように複数のデータを順番に処理する…といったことが難しくなってしまいます。
下のように、オブジェクトのデータを増やしていくのも現実的とは言い難いでしょう。変数(定数)も、際限なく増えてしまうことになるからです。
JavaScript
// オブジェクト
const obj = {
id: 1,
name: "佐藤",
mail: "xxx@xxx.xxx"
}
const obj2 = {
id: 2,
name: "鈴木",
mail: "yyy@yyy.yyy"
}
それでは、複数かつ種類の異なる大量のデータを扱いたい場合はどうすれば良いのでしょうか?
その答えの一つが、オブジェクトを配列にして管理するという方法です。
下のようにオブジェクト形式のデータを配列として一つの変数で管理することで、種類が異なる複数のデータの管理が容易になります。
JavaScript
//オブジェクトのデータを配列として、定数 data に格納
const data = [
{ id: 1, name: "佐藤", mail: "xxx@xxx.xxx" },
{ id: 2, name: "鈴木", mail: "yyy@yyy.yyy" },
{ id: 3, name: "田中", mail: "zzz@zzz.zzz" }
];
このように配列とオブジェクトを組み合わせると、特定のデータセットを取り出すのも非常に簡単にできるようになります。
たとえば鈴木さんのデータセットだけ取り出したければ、以下のように配列の番号で指定すれば、id、name、mailのデータをそれぞれ抽出することが可能です。
JavaScript
console.log(data[1]); // {id: 2, name: '鈴木', mail: 'yyy@yyy.yyy'}
さらに言えば、鈴木さんのmail情報だけを取得するといった処理も、とてもシンプルに記述することができます。
JavaScript
console.log(data[1].mail); // yyy@yyy.yyy
もちろん、どんな場合でもこのオブジェクトを配列にした形式がベストというわけではありませんが、異なる種類のデータ+複数のデータを扱う必要がある場合は、オブジェクトと配列を組み合わせてみるとうまくいくことが多いです。
POINT!
- ・配列は順番の処理に向くが、異なる種類のデータの管理が得意ではない!
- ・オブジェクトは異なる種類のデータ管理に向くが、配列のような処理ができない!
- ・配列とオブジェクトを組み合わせることで、両者のメリットを取り入れることができる!!
map()メソッドで一つ一つ処理をする
JavaScriptに限らず、プログラミングには繰り返しの処理を行う機能が搭載されています。
JavaScriptで言うと、for文(forループ)が有名というか、基本的な反復処理として紹介されることが多いかと思います。
今回やりたいこと(=オブジェクトの配列を展開してリスト表示させること)は、もちろんfor文を用いてもできるのですが、JavaScriptには配列になっているデータに繰り返しの処理を行うための専用のメソッドが用意されています。
その一つが、map( )メソッドです。
map( )メソッドは、配列から一つ一つデータを取り出して処理を行い、新しい配列として生成する…という働きをします。
ちなみに、for文ではなく、map( )メソッドを使って処理を行うメリットとしては、以下のようなものが挙げられます。
- (1)配列データに対して何らかの処理を行って新しい配列を生成していると、一目で判別できる
- (2)配列を取り出すだけでなく、配列に特定の処理を加えるコードをシンプルに記述できる
同じようなことはfor文でもできるけれど、コードの可読性やコードの記述量を考えると、map( )メソッドを使える場面ではmap( )メソッドを使用した方が良いと言えるかと思います。
また、map( )メソッドは、JavaScriptの参考書やブログ記事の解説などでもよく出てきます。
他の人が書いたコードをスムーズに理解できるようにしておく意味でも、繰り返しの処理はfor文だけに頼らない方が良いでしょう。
それではまず、シンプルな処理で、map( )メソッドの使い方と仕組みを確認していきましょう
下は、定数arr1に格納された配列のデータ(数値)に、それぞれ2を掛けた数値を新しい配列(arr2)として生成した例です。
JavaScript
const arr1 = [1,2,3,4];
const arr2 = arr1.map( (x) => {
//arr1に格納された数値を一つ一つ取り出し、2を掛けた数値を戻り値として返す
return x * 2;
});
console.log(arr2); // [2, 4, 6, 8]
console.log(arr1); // 元の配列はそのまま -> [1, 2, 3, 4]
map( )メソッドの( )内の第一引数はコールバック関数を指定します。
上の例では第一引数にそのまま関数を入れていますが、もちろん分けて書くことも可能です。
JavaScriptを学び始めてまだ間もないうちは、下のようにコールバック関数を分けて書いた方が理解しやすいかもしれません。
JavaScript
const arr1 = [1,2,3,4];
// コールバック関数を定義しておく
function multiplyTwo(x) {
return x * 2;
}
// map( )メソッドで配列のデータを一つ一つ取り出し、関数を実行して新しい配列を作成する
const arr2 = arr1.map(multiplyTwo);
console.log(arr2); // [2, 4, 6, 8]
console.log(arr1); // 元の配列はそのまま -> [1, 2, 3, 4]
基本的なmap( )メソッドの使い方は以上です。より詳しく知りたい方はMDN Web Docsのサイトを参考にすると良いでしょう。
さて、map( )メソッドの基本を抑えたらいよいよオブジェクトの配列データを展開してみましょう!
サンプルのコードは次のようになります。
JavaScript
const data = [
{ id: 123, name: "佐藤" },
{ id: 221, name: "鈴木" },
{ id: 317, name: "田中" }
];
const list = data.map( (item) => {
return `<li>${item.name} (ID:${item.id})</li>`;
});
console.log(list); // '<li>佐藤(ID:123)</li>', '<li>鈴木(ID:221)</li>', '<li>田中(ID:317)</li>'
後で<li>要素としてHTMLタグとして埋め込みたいので、テンプレートリテラルを用いて、<li>を含めるように処理しています。
これで無事に、オブジェクトの配列データを展開することができました。
しかし、このままではあくまで使いやすい形の配列に展開できたというだけです。
というわけで次は、新しく作成した配列をHTML要素として挿入するための準備をさらに進めていきたいと思います。
POINT!
- ・繰り返しの処理はfor文以外にも色々ある!
- ・map( )メソッドは、配列に特定の処理を加えて新しい配列を生成する!
- ・map( )メソッドの第一引数はコールバック関数!
文字列として結合する
前章の処理によって、オブジェクトの配列データを扱いやすい配列に変換することができました。
配列のままではそのまま要素として挿入できないので、まずは新しく生成した配列をすべて文字列として結合してしまいましょう。
具体的には、下のような形にしたいということです。
// Before
['<li>佐藤(ID:123)</li>', '<li>鈴木(ID:221)</li>', '<li>田中(ID:317)</li>']
// After
'<li>佐藤(ID:123)</li><li>鈴木(ID:221)</li><li>田中(ID:317)</li>'
実は、配列の結合はjoin( )メソッドを使ってとても簡単にできます。
配列を文字列として結合する際、/(スラッシュ)などの区切り文字を入れる場合は、join( )の引数に区切り文字を指定する必要がありますが、今回は必要ないので引数を省略…したいところですが、そうはいきません。
というのも、join( )の引数を省略すると、デフォルトで,(カンマ)が区切り文字として指定されるからです。
HTML要素として挿入する際、文字列の間に,(カンマ)があると邪魔になってしまうので、join( )の引数には空白を指定して配列を結合します。
JavaScript
const data = [
{ id: 123, name: "佐藤" },
{ id: 221, name: "鈴木" },
{ id: 317, name: "田中" }
];
const list = data.map( (item) => {
return `<li>${item.name} (ID:${item.id})</li>`
});
const listElm = list.join("");
console.log(listElm);
// <li>佐藤 (ID:123)</li><li>鈴木 (ID:221)</li><li>田中 (ID:317)</li>
余計な区切り文字を挟むことなく、無事に文字列として結合することができました。
なお、今回は説明のためにmap( )メソッドによる配列作成と、join( )メソッドによる文字列結合の処理を分けて行いましたが、下のようにまとめて行うことも可能です。
JavaScript
const data = [
{ id: 123, name: "佐藤" },
{ id: 221, name: "鈴木" },
{ id: 317, name: "田中" }
];
const list = data.map( (item) => {
return `<li>${item.name} (ID:${item.id})</li>`
}).join("");
console.log(list);
// <li>佐藤 (ID:123)</li><li>鈴木 (ID:221)</li><li>田中 (ID:317)</li>
慣れれば、こちらの方がコードを短縮できるのでおすすめです。
あとは、この文字列をHTML要素として挿入すれば完成です!
POINT!
- ・配列を文字列として結合したい場合は、join( )メソッドを使おう!
- ・join( )メソッドの引数を省略すると、,(カンマ)が自動で区切り文字になる!
- ・区切り文字をつけたくない場合は、空白を指定しておこう!
HTML要素として挿入
前章の処理で、タグを含む文字列を作ることができました。
あとはこの文字列をHTML要素として挿入すれば完成です。
文字列をHTML要素としてWebページに反映するには、innerHTMLプロパティを使うと簡単ですが、HTMLの内容を置き換えるというより、HTMLを挿入したいという場合はinsertAdjacentHTML( )メソッドを使った方が良いです。
そのためにまず、要素を挿入するための要素(ルートとなる要素)を用意しておく必要があるので、HTMLファイルを編集して準備しておきましょう。
HTML
<div id="root"></div>
そして、getElementByID( )メソッドなどを使ってルートとなる要素情報を取得し、insertAdjacentHTML( )で用意しておいた文字列をHTML要素として挿入していきます。
サンプルコードは下のようになります。
JavaScript
const data = [
{ id: 123, name: "佐藤" },
{ id: 221, name: "鈴木" },
{ id: 317, name: "田中" }
];
const list = data.map( (item) => {
return `<li>${item.name} (ID:${item.id})</li>`;
});
const listElm = list.join("");
const rootElm = document.getElementById("root");
rootElm.insertAdjacentHTML("afterbegin",`<ul>${listElm}</ul>`);
insertAdjacentHTML( )の第一引数には、ルート(基準)となる要素に対する挿入位置を指定します。(第二引数はHTML要素として挿入したい文字列)
サンプルコードの afterbegin は、ルートとなる要素の最初の子要素として挿入するという指定になります。
insertAdjacentHTML( )メソッドについては、このブログ記事でも解説しているので、詳しく知りたい方は下のリンクからぜひご覧ください!
サンプルコードをWebブラウザで表示させると、下のようなリスト形式で表示されます。
- 佐藤(ID:123)
- 鈴木(ID:221)
- 田中(ID:317)
元々はオブジェクトが配列になった複雑なデータでしたが、最終的にHTMLの<li>要素として一つ一つ展開して表示させることに成功しましたね!
ただし、このように文字列をHTML要素として挿入する際は、セキュリティに十分に気をつける必要があります。
たとえば、ユーザーが入力した文字列がそのままHTML要素として反映されるような仕組みになっていると、<script>タグを使って、悪意のあるプログラムを埋め込むことが可能になってしまいます。
メモ帳アプリなど、ユーザーが入力した文字列を反映させる必要がある場合は、文字列をそのまま反映させないような工夫や、エスケープ処理を行うなどして、セキュリティを強化しておくことが大切です。
POINT!
- ・文字列をHTML要素として挿入するには、insertAdjacentHTML( )メソッドを使おう!
- ・insertAdjacentHTML( )の第一引数は挿入位置、第二引数は挿入したい文字列を指定する!
- ・HTML要素として挿入する処理を行う際は、セキュリティの問題に特に注意しよう!
Reactでデータをリストに展開するには
ReactもJavaScriptで動くものなので、基本的にほとんど同じ手順でデータをリストに展開できます。
Reactの場合、JSXによって式を直接埋め込むことができるため、join( )メソッドで文字列に変換する必要がないなどのメリットもありますが、Reactならではの注意点もあります。
それは、<li>要素のkey属性に、一意となる値を指定する必要があるという点です。
今回の例のように、配列のオブジェクトデータに一意となるidなどが含まれている場合は、その値を<li>要素のkey属性として利用すると良いでしょう。
用語解説:一意となる値とは?
下のサンプルコードは、Reactにおけるデータのリスト展開例です。
JavaScript
import React from "react";
const data = [
{ id: 123, name: "佐藤" },
{ id: 221, name: "鈴木" },
{ id: 317, name: "田中" }
];
export default function App() {
const List = () => {
const listItem = data.map( (item) => {
return <li key={item.id}>{item.name} (ID:{item.id})</li>;
});
return <ul>{listItem}</ul>;
}
return <List />;
}
Reactにおけるmap( )メソッドを使ったリスト(li)展開と、key属性について詳しく知りたい方は、下のReact公式ドキュメントをご覧ください。
ちなみに、<li>要素のkey属性の指定を忘れると、下のようなエラーが表示されます。
このようなエラーが表示されたら、<li>要素に一意となるkey属性の値を指定すると、エラーを解決できます。
POINT!
- ・Reactでもほぼ同じ手順でデータをリストに展開することができる!
- ・Reactの場合、JSXで式を直接埋め込めるので、join( )メソッドで文字列として結合する必要がない!
- ・ただし、<li>要素に一意となるkey属性を指定しないとエラーが表示されてしまうので注意が必要!