JavaScript:配列(map/filterが使えるようになる)
音声
目次
配列の基本(追加・削除・参照)
配列は順序付きのデータ集合です。基本操作は短く覚えます。
- 追加:push(末尾へ)です。
- 削除:pop(末尾から取り出す)です。
- 参照:arr[index](0始まり)です。
最小サンプル(CodePenのHTML欄に書きブラウザでボタンを押すと出力)です。
<!-- HTML -->
<button id="run">実行</button>
<pre id="output"></pre>
<script>
// 画面(#output)とConsoleに同じ内容を出すための関数(出力用)
const out = msg => {
const el = document.getElementById('output'); // 表示先の要素を取得
console.log(msg); // Consoleにも出す(確認用)
el.textContent += msg + '\n'; // 画面に追記(\nは改行)
};
// 「実行」ボタン(#run)を押したら、配列の基本操作を順に試す
document.getElementById('run').addEventListener('click', () => {
// 配列:複数の値を順番にまとめる(0番から数える)(実行の度に初期化する)
const nums = [1, 2, 3];
// 現在の配列を表示(JSON.stringifyで配列を文字列にして見やすくする)
out('初期: ' + JSON.stringify(nums));
// push:末尾に追加(元の配列が変わる)
nums.push(4);
out('push後: ' + JSON.stringify(nums));
// pop:末尾を取り出して削除(取り出した値が戻り値)
out('popで取れた: ' + nums.pop());
// nums[1]:2番目の要素(インデックス1)を取り出す
out('nums[1]: ' + nums[1]);
});
</script>
実行で配列の追加・削除・参照の挙動を確認できます。
破壊的変更と非破壊(Reactで重要)
配列操作は「元を変えるか(破壊的)」「新しい配列を返すか(非破壊)」で分かれます。Reactなど参照比較で差分を検出する場面では非破壊が基本です。
破壊的:push, pop, splice, sort, reverse(元の配列が変わります)
非破壊:map, filter, slice, concat, spread(...)など(新しい配列を返します)
例:コピーしてから追加する(非破壊)
// 例(CodePenのJS欄に貼る)
const a = [10, 20, 30];
// ...a は「a の中身を展開して並べる」なので、新しい配列を作れる(a自体は変わらない)
const b = [...a, 40]; // b = [10, 20, 30, 40]
// push は元の配列 a に直接追加するので、a が変わる(破壊的)
a.push(40); // a = [10, 20, 30, 40]
console.log(b)
console.log(a)
ポイント:sort()やreverse()は「新配列が返る」と誤解されやすく、Stateを直接変えてしまうミスが多いです。必要ならコピーしてから使うとよいです([...arr].sort())。
mapで「変換」、filterで「絞り込み」
mapとfilterは読みやすく、組み合わせやすい非破壊メソッドです。
- mapは各要素を変換して、同じ長さの新配列を作ります。
- filterは条件で要素を絞り込み、長さが短くなることがある新配列を作ります。
例です。
// 例(CodePenのJS欄に貼る)
const users = [
// ユーザーの一覧:id / 名前 / 利用中か(true=利用中)
{ id: 1, name: 'A', active: true },
{ id: 2, name: 'B', active: false }
];
// map:配列の各要素を「変換」して、新しい配列を作る(ここでは名前だけ取り出す)
const names = users.map(u => u.name); // ['A', 'B']
// filter:条件に合う要素だけを「残して」新しい配列を作る(ここでは active が true の人だけ)
const active = users.filter(u => u.active); // [{id:1,name:'A',active:true}]
// 組み合わせ:まず active の人だけに絞って、その後に名前だけ取り出す
const activeNames = users.filter(u => u.active).map(u => u.name); // ['A']
console.log('names:', names);
console.log('active:', active);
console.log('activeNames:', activeNames);
更新(idで一致する要素だけ更新)はmap、削除はfilterが自然です。
find/some/everyで判定する
検索・存在チェック・全件チェックは専用メソッドが明確です。
- find:条件に合う最初の要素が返ります(見つからなければ undefined になります)。
- some:条件に合う要素が1つでもあるかどうかが boolean で返ります。
- every:全要素が条件を満たすかどうかが boolean で返ります。
例:
// 例(CodePenのJS欄に貼る)
// 在庫データ(sku=商品コード、stock=在庫数)
const items = [
{ sku: 'A', stock: 3 },
{ sku: 'B', stock: 0 }
];
// find:条件に合う「最初の1件」を返す(なければ undefined)
const firstOutOfStock = items.find(i => i.stock === 0);
// → { sku: 'B', stock: 0 }
// some:条件に合うものが「1つでもあるか」を true/false で返す
const hasOutOfStock = items.some(i => i.stock === 0);
// → true(在庫0の商品がある)
// every:全てが条件を満たすかを true/false で返す
const allInStock = items.every(i => i.stock > 0);
// → false(在庫0があるので「全て在庫あり」ではない)
console.log('firstOutOfStock:', firstOutOfStock);
console.log('hasOutOfStock:', hasOutOfStock);
console.log('allInStock:', allInStock);
findの戻り値は undefined になるケースを考慮して扱うことがポイントです。
reduceは必要な範囲だけ
reduceは「配列を1つの値(数、オブジェクト、Mapなど)に畳み込む」ための強力なツールです。ですが何でもreduceにするのは可読性低下の元なので、目的が「集約」かどうかで使うか判断します。
例:合計と集計オブジェクトです。
// 例(CodePenのJS欄に貼る)
// カートの中身(name=商品名、price=単価、qty=個数)
const cart = [
{ name: 'B', price: 1200, qty: 2 },
{ name: 'P', price: 200, qty: 3 }
];
// reduce:配列を「1つの結果」にまとめるときに使う(合計・集計など)
// 例1:合計金額を計算する(s は合計、it は各商品)
// 初期値 0 から始めて、(単価×個数) を足していく
const total = cart.reduce((s, it) => s + it.price * it.qty, 0); // 3000
// 例2:商品名ごとの個数をまとめたオブジェクトを作る(acc が集計結果)
// acc['B']=2, acc['P']=3 のように入れていき、最後に acc を返す
const byName = cart.reduce((acc, it) => {
acc[it.name] = it.qty;
return acc;
}, {});
console.log('total:', total); // 3000
console.log('byName:', byName); // {B: 2, P: 3}
変換はmap、絞り込みはfilter、集約が目的ならreduceと覚えておくと良いです。
貼り付け場所: 今回は、CodePenなら目次1のコードはHTML欄のみ、その他の例はJS欄のみへの貼付けで動作します。
実行方法: ブラウザで開くか、CodePenのRunで実行します。Consoleで結果を見ます。
確認方法: console.logの出力や画面表示が想定どおりかで確認します(必要なら簡単な条件チェックもします)。
よくあるミス: Consoleを開いていないため出力が見えない、または変数名のスペル違いでReferenceErrorになることがあります。
使い分けの基準: 繰り返しはfor/for...of、変換はmap、絞り込みはfilterのように目的で使い分けます。
注意(ここだけ)
sort()/reverse()/splice()は配列を破壊的に変更します。元を残したいならコピーしてから使います(例:[...arr].sort())。for...inは配列向きではありません(キー列挙なので順序や拡張プロパティで事故ります)。配列はfor...ofやmapを使います。map/filter内で外側の変数を書き換えると追跡が難しくなります。できるだけ「入力→出力」を純粋にします。
要約
配列はpushやpopで要素を追加・削除し、arr[index]で参照するのが基本です。
破壊的変更と非破壊を区別し、Reactなど参照比較がある場面では非破壊の操作を優先するのがポイントです。
mapは「変換」、filterは「絞り込み」に使い、組み合わせて使うと意図が伝わりやすいです。
find/some/everyで検索・存在確認・全件チェックを明確にできます。findは未発見時にundefinedを返す点は要チェックです。
reduceは合計やグルーピングなど「集約」が目的のときに限定して使うと読みやすいです。