テーマの整理:「配列キャッシュ」とは何か
「配列キャッシュ」は、一度計算した「配列に対する結果」を覚えておいて、同じ入力に対しては再計算せずに使い回すための仕組みです。 業務だと、こんな場面で欲しくなります。
API から取得した一覧データを、何度も同じ条件でフィルタ・ソートしている。 重い計算(集計・統計)を、同じ配列に対して何度も繰り返している。 画面の再描画のたびに、同じ配列処理を何度もやっていて、パフォーマンスが気になる。
こういうときに「配列キャッシュ」を入れておくと、“一度やった計算を覚えておく”ことで、処理が軽くなります。
基本コンセプト:入力(配列)と結果を紐づけて覚える
「キー」と「値」をどう決めるか
キャッシュの基本は、「キー」と「値」です。
キー:何に対する結果かを識別するもの。 値:その結果そのもの。
配列キャッシュの場合、 「どの配列に対して」「どんな条件で」計算した結果なのかをキーにして、 「計算結果の配列や数値」を値として保存します。
シンプルな形:JSON 文字列をキーにする
初心者向けに一番分かりやすいのは、 配列を JSON.stringify して文字列にし、それをキーにする方法です。
const cache = new Map();
function getFromCacheOrCompute(array, computeFn) {
const key = JSON.stringify(array);
if (cache.has(key)) {
return cache.get(key);
}
const result = computeFn(array);
cache.set(key, result);
return result;
}
JavaScriptここでは、
cache は「キー → 結果」を覚えておく Map。 key は「配列を文字列化したもの」。 computeFn は「配列から結果を計算する関数」。
という役割になっています。
例題 1:重い集計処理をキャッシュする
シナリオ
売上データの配列があり、 「合計金額」を出す処理が重い(件数が多い)。 同じ配列に対して何度も合計を出すなら、キャッシュしたい。
コード
const sumCache = new Map();
function sumWithCache(items) {
const key = JSON.stringify(items);
if (sumCache.has(key)) {
console.log("use cache");
return sumCache.get(key);
}
console.log("compute");
const total = items.reduce((acc, item) => acc + item.amount, 0);
sumCache.set(key, total);
return total;
}
const data = [
{ id: 1, amount: 100 },
{ id: 2, amount: 200 },
{ id: 3, amount: 300 },
];
console.log(sumWithCache(data)); // compute → 600
console.log(sumWithCache(data)); // use cache → 600
JavaScriptここでのポイントは、
最初の呼び出しでは compute が走り、合計を計算してキャッシュに保存する。 2 回目以降は use cache になり、計算せずにキャッシュから取り出す。
「同じ配列に対して同じ処理を何度もする」場面では、こういうキャッシュが効いてきます。
例題 2:フィルタ結果をキャッシュする(条件付き)
シナリオ
ユーザー一覧の配列があり、 「active なユーザーだけを取り出す」処理を何度も呼び出している。 配列と条件の組み合わせでキャッシュしたい。
コード
const filterCache = new Map();
function filterActiveWithCache(users, activeOnly) {
const key = JSON.stringify({ users, activeOnly });
if (filterCache.has(key)) {
console.log("use cache");
return filterCache.get(key);
}
console.log("compute");
const result = activeOnly
? users.filter((u) => u.active)
: users.slice();
filterCache.set(key, result);
return result;
}
const users = [
{ id: 1, name: "A", active: true },
{ id: 2, name: "B", active: false },
{ id: 3, name: "C", active: true },
];
console.log(filterActiveWithCache(users, true)); // compute
console.log(filterActiveWithCache(users, true)); // use cache
console.log(filterActiveWithCache(users, false)); // compute
console.log(filterActiveWithCache(users, false)); // use cache
JavaScriptここでは、
キーに「配列」と「条件(activeOnly)」をまとめて入れている。 同じ配列+同じ条件なら、結果を再利用できる。
という形になっています。
重要ポイント:キャッシュの「有効期限」と「更新」
配列が変わったらキャッシュは古くなる
キャッシュは「同じ入力に対して同じ結果が欲しい」前提で成り立っています。 つまり、配列の中身が変わったら、本来はキャッシュを無効にしないといけません。
例えば、
ユーザー一覧に新しいユーザーが追加された。 売上データに新しいレコードが増えた。
こういうときに「古い配列をキーにしたキャッシュ」を使い続けると、 結果が古いままになってしまいます。
シンプルな対策:配列を「毎回新しく作る」前提で使う
React やフロントエンドでは、 「状態を更新するときは新しい配列を作る(イミュータブル)」というスタイルが多いです。
この場合、
新しい配列 → 新しいキー → 新しいキャッシュ 古い配列 → 古いキー → 古いキャッシュ
というふうに自然に分かれるので、 「配列キャッシュ」が比較的安全に使えます。
初心者向けには、
配列を直接書き換えるより、array.slice() や array.map() などで新しい配列を作る。 キャッシュは「配列の内容が変わったら別物」として扱う。
という感覚を持っておくとよいです。
もう一歩進んだ形:関数としての「配列キャッシュユーティリティ」
createArrayCache:どんな処理にも使える汎用キャッシュ
毎回 Map を手で書くのではなく、 「配列を受け取って結果を返す関数」をラップするユーティリティを作ると便利です。
function createArrayCache(computeFn) {
const cache = new Map();
return function cached(array, options = {}) {
const key = JSON.stringify({ array, options });
if (cache.has(key)) {
return cache.get(key);
}
const result = computeFn(array, options);
cache.set(key, result);
return result;
};
}
JavaScript使い方はこうです。
function sumAmounts(items) {
return items.reduce((acc, item) => acc + item.amount, 0);
}
const sumAmountsCached = createArrayCache(sumAmounts);
const data = [
{ id: 1, amount: 100 },
{ id: 2, amount: 200 },
];
console.log(sumAmountsCached(data)); // 計算
console.log(sumAmountsCached(data)); // キャッシュ
JavaScriptここでのポイントは、
computeFn に「配列から結果を計算する関数」を渡す。 createArrayCache が「キャッシュ付きバージョン」を返してくれる。 呼び出し側は「普通の関数」と同じ感覚で使える。
という構造になっていることです。
配列キャッシュを使うときに意識してほしいこと
「本当にキャッシュが必要か?」を考える
キャッシュは便利ですが、 むやみに入れるとコードが複雑になり、バグの原因にもなります。
考えてほしいポイントは、
その計算は本当に重いか? 同じ入力に対して何度も呼び出されるか? 結果が変わらないことが前提になっているか?
これらに「はい」が多いほど、配列キャッシュを入れる価値が高いです。
「いつキャッシュを捨てるか?」を決める
キャッシュは「溜めっぱなし」にすると、 メモリを食い続けたり、古い結果を使い続けたりします。
シンプルな対策としては、
画面単位・処理単位で Map を作り直す(スコープを限定する)。 一定件数を超えたら古いキーを削除する。
などがありますが、初心者のうちは 「まずはスコープを小さくする(関数の中だけで Map を使う)」 くらいから始めるのがちょうどいいです。
手を動かして「配列キャッシュ」の感覚をつかむ
次のコードを実行して、「キャッシュあり/なし」の違いを体感してみてください。
const sumCache = new Map();
function sumWithCache(items) {
const key = JSON.stringify(items);
if (sumCache.has(key)) {
console.log("use cache");
return sumCache.get(key);
}
console.log("compute");
const total = items.reduce((acc, item) => acc + item.amount, 0);
sumCache.set(key, total);
return total;
}
function sumWithoutCache(items) {
console.log("always compute");
return items.reduce((acc, item) => acc + item.amount, 0);
}
const data = [
{ id: 1, amount: 100 },
{ id: 2, amount: 200 },
{ id: 3, amount: 300 },
];
console.log("=== with cache ===");
console.log(sumWithCache(data));
console.log(sumWithCache(data));
console.log("=== without cache ===");
console.log(sumWithoutCache(data));
console.log(sumWithoutCache(data));
JavaScriptログを見れば、
キャッシュあり:1 回目だけ「compute」、2 回目は「use cache」。 キャッシュなし:毎回「always compute」。
という違いがはっきり分かるはずです。
まとめ:配列キャッシュユーティリティで「一度やった計算を賢く使い回す」
配列キャッシュは、 「同じ配列に対して何度も同じ計算をするなら、一度だけ計算して覚えておこう」 という、とても人間的な発想をコードにしたものです。
プロジェクトに例えば次のような形で置いておくイメージです。
export function createArrayCache(computeFn) { ... }
export const sumAmountsCached = createArrayCache(sumAmounts);
JavaScriptそして、「重い配列処理で、同じ入力が何度も来るところにはキャッシュを挟む」と決めておく。 それだけで、パフォーマンスが安定し、 「どこで計算していて、どこで結果を使い回しているか」がコードから読み取りやすくなります。
キャッシュは“魔法”ではなく、“覚えておく工夫”です。 配列キャッシュユーティリティをうまく使うと、 業務コードがぐっと落ち着いた動き方をするようになります。
