JavaScript | 配列・オブジェクト:パフォーマンス・設計 – 実務でのベストプラクティス

JavaScript JavaScript
スポンサーリンク

実務でのベストプラクティスとは何か

「ベストプラクティス」とは、現場で繰り返し使われてきた“安全で効率的なやり方”のことです。JavaScript の配列・オブジェクト操作では、可読性・性能・安全性のバランスを取ることが重要です。ここが重要です:初心者は「動けばいい」から始めますが、実務では「壊れにくく、速く、読みやすい」コードが求められます。


非破壊操作を基本にする

元データを壊さない設計

配列やオブジェクトを直接書き換えると、他のモジュールやUIが参照している場合に副作用が発生します。実務では「非破壊操作」を基本にします。

// 悪い例:破壊的
arr.sort((a, b) => a.price - b.price); // arr が書き換わる

// 良い例:非破壊的
const sorted = arr.toSorted((a, b) => a.price - b.price); // arr はそのまま
JavaScript

ここが重要です:UIフレームワーク(React/Vueなど)は“参照の変化”で差分検知を行うため、非破壊更新が必須です。


filter / map / reduce の使い分け

意図を明確にする

  • filter: 条件で絞り込み
  • map: 形を変換
  • reduce: 集計や構造変換
const activeUsers = users.filter(u => u.active);
const names = activeUsers.map(u => u.name);
const totalAge = activeUsers.reduce((sum, u) => sum + u.age, 0);
JavaScript

ここが重要です:filter→map→reduce を組み合わせると意図が明快になります。ただし大量データでは中間配列が増えるため、1パス融合(for…of)で最適化することもあります。


データ構造を正しく選ぶ

配列 vs 辞書 vs Set

  • 配列: 順序や全件処理に強い
  • オブジェクト/Map: ID検索や部分更新に強い
  • Set: 存在チェックや重複排除に強い
// 配列で順序を保持
const rows = [{ id: 1 }, { id: 2 }];

// 辞書で即アクセス
const dict = Object.fromEntries(rows.map(r => [r.id, r]));
console.log(dict[2]); // O(1)でアクセス

// Setで存在判定
const seen = new Set([1,2,3]);
console.log(seen.has(2)); // true
JavaScript

ここが重要です:構造を選ぶだけで計算量が劇的に変わります。検索が多いなら辞書、存在判定なら Set を選ぶのが鉄則です。


正規化(entities)で更新を効率化

配列と辞書を分ける設計

一覧表示と部分更新を両立するために「正規化」します。配列は順序用、辞書は検索・更新用に分けます。

function normalize(users) {
  return {
    entities: Object.fromEntries(users.map(u => [u.id, u])),
    result: users.map(u => u.id)
  };
}

const { entities, result } = normalize(users);
const updated = { ...entities, [2]: { ...entities[2], active: true } };
const view = result.map(id => updated[id]);
JavaScript

ここが重要です:同じレコードを複数コピーせず、唯一の更新源に集約することで不整合を防ぎます。


計算量とメモリを意識する

走査回数を減らす

filter→map→reduce の連鎖は分かりやすいですが、走査が複数回になります。大量データでは1パスでまとめると速くなります。

function filterMap(arr, pred, mapFn) {
  const out = [];
  for (const x of arr) if (pred(x)) out.push(mapFn(x));
  return out;
}
JavaScript

ここが重要です:小規模では可読性優先、大規模では速度優先。計測して切り替えるのが実務的です。


早期終了を活用する

全件走査を避ける

map/filter は最後まで走査しますが、find/some/every は途中で止まれます。

const hit = users.find(u => u.id === 123);   // 見つかれば即終了
const hasActive = users.some(u => u.active); // trueなら即終了
JavaScript

ここが重要です:不要な走査を避けるだけで大幅に速くなります。


ネスト更新は階層ごとにコピーする

部分更新の安全な方法

const state = { user: { flags: { vip: false } } };
const next = {
  ...state,
  user: { ...state.user, flags: { ...state.user.flags, vip: true } }
};
JavaScript

ここが重要です:一段でもコピーを省くと参照共有が残り、副作用が発生します。必要階層だけコピーするのがベストプラクティスです。


まとめ

実務でのベストプラクティスは「非破壊操作を基本に」「filter/map/reduce を意図ごとに使い分け」「構造を正しく選ぶ」「正規化で更新を効率化」「走査回数を減らす」「早期終了を活用」「ネストは階層ごとにコピー」です。ここが重要です:初心者はまず可読性を優先し、計測して必要な箇所だけ速度を最適化する。この指針に従えば、読みやすく壊れにくく、実務に耐える配列・オブジェクト処理が書けます。

タイトルとURLをコピーしました