JavaScript | ES6+ 文法:新データ構造 – 実務利用判断

JavaScript JavaScript
スポンサーリンク

まずゴールをはっきりさせる:何を判断したいのか

ES6 の「新データ構造」と言われると、

  • Map / Set
  • WeakMap / WeakSet

が一気に出てきて、「全部使えたほうがいいのかな?」と身構えがちです。

でも実務的には、いきなり全部をフル活用する必要はありません。

実務で大事なのは、

  • どんな場面で
    「Object / Array より Map / Set を選ぶべきか」
  • どんな場面で
    「WeakMap / WeakSet を使う“価値がある”のか」

を見分けられることです。

ここが重要です。
「何でも新データ構造を使う」のではなく、「こういうときはこれ」と選べることが、実務での強さになります。

実務でよく使うのは「Map」と「Set」

まず優先度:Map / Set を日常的な武器にする

実務レベルで本当によく使うのは、断トツで MapSet です。

WeakMap / WeakSet は「知っておくと得」くらいで、
毎日のように出てくるのは Map / Set の方です。

ですから判断のスタート地点はこうです。

  • これは Object / Array で書いているけど、
    Map / Set にしたほうが素直じゃないか?

この視点で、自分のコードを見直してみるのが一番現実的です。

Array vs Set:重複・存在チェック・集合っぽさ

次のようなコードを書いていたら、Set を検討する価値が高いです。

  • 配列に値をどんどん push している
  • その前に includesindexOf で「もう入ってるかどうか」をチェックしている
  • 「重複を消したい」と思っている

典型的な例を見てみます。

// よくある「配列だけで頑張る」パターン
const visited = [];

function visit(page) {
  if (!visited.includes(page)) {
    visited.push(page);
  }
}
JavaScript

これが Set だとこうなります。

const visited = new Set();

function visit(page) {
  visited.add(page); // 重複なら自動で無視
}
JavaScript

「重複を気にする」仕事を Set に丸投げできるので、
コードが短くなるだけでなく、意図が明確になります。

ここが重要です。
「要素の順番+重複OK」なら Array。
「順番+重複NG」なら Set。

この軸で考えると、「どちらを使うべきか」の判断がかなり楽になります。

Object vs Map:辞書・マップらしく扱いたいとき

次のようなコードを書いていたら、Map を検討する価値が高いです。

  • Object に動的にキーを追加・削除している
  • 「キーの数」を頻繁に知りたい
  • 「存在チェック」「削除」をよくする
  • キーに数値やオブジェクトを使いたい

よくある「ユーザーID → ユーザー」を Object でやるケース:

// Object で辞書をやっている例
const users = {};

function addUser(user) {
  users[user.id] = user;
}

function getUser(id) {
  return users[id];
}

function getUserCount() {
  return Object.keys(users).length;
}
JavaScript

これを Map にすると:

const users = new Map();

function addUser(user) {
  users.set(user.id, user);
}

function getUser(id) {
  return users.get(id);
}

function getUserCount() {
  return users.size;
}
JavaScript

サイズ取得、存在チェック、削除、ループなど、
すべて Map のメソッドで書けて、コードの意図がかなり読みやすくなります。

ここが重要です。
「1件のデータの属性」なら Object、「たくさんのキーと値の集まり」なら Map。
実務では、このラインを意識するだけで設計の見通しが一段上がります。

具体的な判断フロー(Map / Set を使うか?)

まず自分に問うべき質問

コードを書いていて迷ったら、こんな質問を自分に投げてみてください。

これは「1件の情報」か?「たくさんの集まり」か?

  • 1人のユーザーの id, name, age → Object
  • たくさんのユーザーを id で引きたい → Map
// Object が自然
const user = { id: 1, name: "Alice", age: 20 };

// Map が自然
const userById = new Map();
userById.set(1, user);
JavaScript

重複を許したいか?許したくないか?

  • 同じ値が何度も登場してもいい履歴 → Array
  • 「一度でも登場したかどうか」が本質 → Set
// クリック履歴(何度クリックされたかも意味がある)→ Array
const clickHistory = [];

// どのページを一度でも訪れたかだけが重要 → Set
const visitedPages = new Set();
JavaScript

キーにオブジェクトを使いたいか?

  • 使わない(文字列 / 数値キーだけ) → Object or Map
  • 使いたい(DOM 要素やオブジェクトそのもの) → Map 一択
// DOM 要素に追加情報を紐づけたい
const stateByElement = new Map();

stateByElement.set(someDomElement, { hovered: false });
JavaScript

実務的な優先順位

実用順に並べると、こうなります。

  1. Array / Object(これがベース)
  2. そこから卒業する形で Set / Map
  3. さらに特殊な場面で WeakMap / WeakSet

無理に「最初から全部新データ構造で!」としなくてよくて、
Array / Object で書いたものを、

  • 「これ、Set / Map の方が意味としてしっくりくるな」
  • 「ここ、includes / Object.keys.length を何度も書いていてダルいな」

というポイントから少しずつ置き換えていく方が、身になり方も現実的です。

WeakMap / WeakSet を実務で使うかどうかの判断

結論:初心者は「存在を知っておけば十分」

正直にいうと、
フロントエンドでもバックエンドでも、WeakMap / WeakSet を毎日触る人はそんなに多くありません。

ただし、「ここで WeakMap 使えるな」と気づける人は、
メモリや設計に対する感度が高いです。

なので、初心者のうちは:

  • 「オブジェクトに付随情報を持たせたい」
  • 「でも、そのせいでメモリリークさせたくない」

という状況が見えたときに、
「そういえば WeakMap / WeakSet ってあったな」と思い出せれば十分です。

実務で WeakMap / WeakSet を使うべき条件

次の 2 つが揃っていたら、Weak 系を検討する価値があります。

  1. キー or 要素に「オブジェクト(特に DOM やクラスインスタンス)」を使いたい
  2. そのオブジェクトが不要になったとき、「自動で紐づいた情報も消えてほしい」(= メモリリークを避けたい)

例えば、DOM 要素 → 付随情報のマップ:

// WeakMap の利用が検討できるパターン
const extraData = new WeakMap();

function attach(el, data) {
  extraData.set(el, data);
}

function getData(el) {
  return extraData.get(el);
}
JavaScript

ここで普通の Map を使うと、

  • DOM を削除しても
  • Map が要素を参照し続けるので
  • GC で回収されない → メモリリークのリスク

WeakMap なら、要素が他から参照されなくなれば、
付随情報ごと GC の対象になります。

「一覧したい」「数えたい」なら Weak 系は選ばない

次のように思った瞬間、WeakMap / WeakSet は候補から外れます。

  • 中身を全部ループしたい
  • 何個登録されているか size で見たい

Weak 系はそもそも「列挙もサイズもできない設計」なので、
そういう用途には向きません。

ここが重要です。
WeakMap / WeakSet は、「既に知っているオブジェクトに対して、こっそり情報をくっつける」ためのツール。
全体を管理・監視するツールではない。

小さな実務風シナリオで判断を体感する

シナリオ1:ToDo アプリの内部データ

ToDo アプリを考えます。

  • 1 件のタスク(id, title, done) → Object
  • タスクの一覧 → Array or Map?

ここではこう分けるのが自然です。

// 1件のタスク
const todo = {
  id: 1,
  title: "牛乳を買う",
  done: false,
};

// タスク一覧(ID で検索したいなら Map が便利)
const todosById = new Map();
todosById.set(todo.id, todo);
JavaScript
  • 「表示順」が大事なら Array(+必要に応じて Map を併用)
  • 「id から一発で取りたい」が大事なら Map

という風に、「何が一番大事な操作か」で選びます。

シナリオ2:ログイン中ユーザーの管理

  • 要件:ユーザーIDごとに「ログイン中のユーザー情報」を持ちたい
  • 操作:ログイン / ログアウト / 現在のログイン人数

こういう要件は Map がぴったりです。

const loggedInUsers = new Map();

function login(user) {
  loggedInUsers.set(user.id, user);
}

function logout(userId) {
  loggedInUsers.delete(userId);
}

function getCurrentUserCount() {
  return loggedInUsers.size;
}
JavaScript

ここを普通の Object でやると、
Object.keys(users).length が出てきたりして、
「辞書を頑張って自前実装している」感じになります。

シナリオ3:イベント登録済みの DOM を覚えておく

  • 要件:同じ DOM 要素に何度もイベントを登録したくない
  • DOM は消えることもあり、そのとき余計な情報も消えてほしい

ここは WeakSet を検討できます。

const registered = new WeakSet();

function ensureClickHandler(el) {
  if (registered.has(el)) return;

  el.addEventListener("click", () => {
    console.log("clicked");
  });
  registered.add(el);
}
JavaScript

DOM が削除され、他からも参照されなくなれば、
WeakSet 内の記録も GC により消えます。

同じことを Set でやると、
「削除された DOM への参照」が残り続け、
メモリをじわじわ食い続ける可能性があります。

まとめ:新データ構造を「いつ実務に投入するか」

最後に、実務での判断をシンプルな軸にまとめます。

Map / Set を使うべきか?

自分のコードにこういう症状が出ていたら、Map / Set を検討してよいサインです。

  • Object を「辞書」のように扱っている(動的にキーを増やす・消す・数える)
  • 配列+includes で「重複チェック」をよく書いている
  • ある ID やキーから、対応するデータを即座に引きたい
  • 要素数(サイズ)を頻繁に知りたい

このどれかに当てはまるなら、
Array / Object から Map / Set に一歩踏み出していいタイミングです。

WeakMap / WeakSet を使うべきか?

次の条件を満たしたときだけです。

  • キー or 要素に「オブジェクト(特に DOM / インスタンス)」を使いたい
  • そのオブジェクトが不要になったとき、自動で追加情報も消えてほしい
  • 中身を列挙したり、個数を数えたりする必要はない

それ以外の場面では、
「まず Map / Set でいいか?」と考えるほうが安全です。


最初から正解を一発で選べる必要はありません。
大事なのは、こうやって

  • これは「集合」だから Set
  • これは「辞書」だから Map
  • これは「1件のデータ」だから Object

と、自分なりの言葉で説明できるようになることです。

そこまで来たら、あなたはすでに「実務で新データ構造を判断して使いこなせる人」の入り口にいます。
あとは、自分の既存コードの一部を少しずつ Map / Set に置き換えていく中で、
「どこが楽になったか」「どこが気持ちいいか」を、実感で掴んでいってください。

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