JavaScript

JavaScriptのMap.getOrInsertComputed():未登録のキーだけ初期値を作る

この記事でわかること

Map.getOrInsertComputed()で未登録のキーにだけ初期値を作る方法を解説。引数・戻り値、ブラウザーとNode.jsの対応と実行手順、期待出力、例外や参照共有の注意点を学べます。

目的:取得と初期化をひとつにまとめる

担当者ごとの作業情報をMapで管理するとき、「登録済みなら取得し、未登録なら初期情報を作って保存する」という処理が必要になります。Map.prototype.getOrInsertComputed()は、この分岐をまとめるメソッドです。

特徴は、初期値を作る関数がキーの未登録時だけ呼ばれることです。同じ担当者を何度参照しても、登録済みの情報を再利用できます。設定ファイルの解析結果や、初期化に手間のかかるオブジェクトを保持する場合にも役立ちます。

この記事では、担当者ごとの作業ボックスを必要になった時点で作ります。作成回数も表示するため、値の取得と初期化の違いを出力から確認できます。

動作環境と対応バージョン

2026年11月1日時点の確認では、ブラウザーとNode.jsの両方で利用できます。ただし、新しいメソッドなので、古い実行環境での利用を前提にしてはいけません。

  • ブラウザーの実行例はChrome 145以降を対象にします。公式リリースノートに本メソッドの追加が記載されています。
  • Node.jsの実行例は26.0.0以降を対象にします。26.0.0の公式リリースノートで追加を確認できます。
  • MDNではBaseline 2026で、2026年2月から最新の主要ブラウザーで利用可能とされています。古い端末やブラウザーでは利用できない場合があります。

対応根拠はChrome 145のリリースノートとNode.js 26.0.0のリリースノートです。主要ブラウザー全体についてはMDNの互換性情報も参照してください。

実行前に機能の有無を確認する

バージョン番号だけで判断せず、実際の環境で次の式を確認すると確実です。

JavaScript
console.log(typeof Map.prototype.getOrInsertComputed);

対応環境ではfunction、未対応環境では通常undefinedと表示されます。後述の完成コードにも確認処理を入れています。未対応なら本処理を実行せず、説明を表示します。

引数と戻り値

基本の呼び出し方は次のとおりです。

JavaScript
const map = new Map();
const value = map.getOrInsertComputed("alice", (key) => ({
  owner: key,
  tasks: []
}));
console.log(value.owner);

期待出力はaliceです。

  • 第1引数のkeyは、取得または登録するキーです。
  • 第2引数のcallbackは、キーが未登録のときに保存する値を返す関数です。引数として、そのキーを受け取ります。
  • 戻り値は、登録済みの値、または今回作成して保存した値です。

初期値を作る関数を渡す位置では、関数をその場で呼び出さないことが大切です。createBoxを渡すと呼び出しを任せられますが、createBox()と書くと、メソッドに渡す前に実行されます。

仕様上の引数・戻り値・例外はMDNのメソッド解説で確認できます。

コピーして実行できる完成コード

次のコードは外部ライブラリー、通信、画面の要素を使いません。対応ブラウザーとNode.jsで同じ内容を実行できます。

JavaScript
(() => {
  "use strict";

  if (typeof Map.prototype.getOrInsertComputed !== "function") {
    console.log("未対応環境です。対応バージョンで実行してください。");
    return;
  }

  const boxes = new Map();
  let createdCount = 0;

  function createBox(owner) {
    createdCount += 1;
    console.log(`初期化: ${owner}`);
    return { owner, tasks: [] };
  }

  const first = boxes.getOrInsertComputed("alice", createBox);
  first.tasks.push("仕様確認");

  const second = boxes.getOrInsertComputed("alice", createBox);
  second.tasks.push("実装");

  const third = boxes.getOrInsertComputed("bob", createBox);
  third.tasks.push("レビュー");

  console.log(`作成回数: ${createdCount}`);
  console.log(`同じ参照: ${first === second}`);
  console.log(`alice: ${first.tasks.join(" / ")}`);
  console.log(`bob: ${third.tasks.join(" / ")}`);
  console.log(`登録数: ${boxes.size}`);
})();

ブラウザーでの実行方法

Chrome 145以降で開発者ツールを開き、Consoleに完成コード全体を入力して実行します。結果はページ本体ではなくConsoleに表示されます。再実行しても変数名が衝突しにくいよう、全体を即時実行関数で囲んでいます。

Node.jsでの実行方法

Node.js 26.0.0以降を用意し、完成コードをUTF-8のmap-boxes.cjsとして保存します。ターミナルで保存先のフォルダーを開き、次のコマンドを実行します。

Shell
node --version
node map-boxes.cjs

最初のコマンドで利用中のバージョンを確認できます。このコードはモジュールの読み込みを必要とせず、追加パッケージのインストールも不要です。

期待出力と処理の流れ

対応環境での期待出力は次のとおりです。これはコードと仕様から導いたもので、実機で実行した結果ではありません。

CODE
初期化: alice
初期化: bob
作成回数: 2
同じ参照: true
alice: 仕様確認 / 実装
bob: レビュー
登録数: 2

最初のaliceは未登録なのでcreateBoxが呼ばれます。2回目のaliceでは保存済みのオブジェクトが返り、作成回数は増えません。bobは別のキーなので、新しいボックスが作られます。

firstとsecondが同じ参照である点にも注目してください。取得するたびにコピーされるわけではありません。second.tasksへの追加がfirst.tasksからも見えるのは、同じ配列を参照しているためです。

Mapのキーや値の基本的な扱いはMDNのMap解説を参照してください。

失敗例と制約

関数ではなく計算結果を渡してしまう

次のコードは、初期値の作成関数を先に呼び出す失敗例です。対応環境で、完成コードとは別に実行してください。

JavaScript
(() => {
  const map = new Map();

  function createValue() {
    console.log("先に実行された");
    return 100;
  }

  try {
    map.getOrInsertComputed("item", createValue());
  } catch (error) {
    console.log(error instanceof TypeError);
  }
})();

期待出力は次のとおりです。

CODE
先に実行された
true

第2引数に渡るのは関数ではなく数値の100なので、TypeErrorになります。修正する場合はcreateValue()をcreateValueに変更します。

初期化処理の例外は呼び出し側で扱う

初期化関数の中で例外が発生する可能性があるなら、呼び出しをtry...catchで囲みます。次の例は、コールバック自身がMapを書き換えない場合です。

JavaScript
(() => {
  const map = new Map();

  try {
    map.getOrInsertComputed("item", () => {
      throw new Error("初期化失敗");
    });
  } catch (error) {
    console.log(error.message);
  }

  console.log(map.has("item"));
})();

期待出力は初期化失敗、続いてfalseです。値を返す前に例外となるため、この呼び出しによる登録は行われません。

非同期処理と保存期間は別に設計する

本メソッドは同期的にコールバックの戻り値を保存します。async関数を渡すと、保存されるのは完了後のデータではなくPromiseです。失敗したPromiseも残るため、再試行には削除方針が必要です。入門段階では、この記事のような同期的な初期化から始めると挙動を追いやすくなります。

また、オブジェクトをキーにする場合は内容ではなく参照で区別されます。同じ内容のオブジェクトを毎回作ると、別のキーとして登録されます。担当者IDのような安定した文字列をキーにすると、意図した再利用につながります。

活用事例と導入時の改善ポイント

活用しやすいのは、担当者ごとの作業ボックス、画面ごとの編集状態、識別子ごとの解析済み設定などです。「同じキーには同じ保存値を返したい」という要件に適しています。

導入時は、初期化処理と日常的な更新処理を分けてください。完成コードでは、初期化はcreateBox、作業追加は取得後のpushです。初期化関数に毎回必要な処理まで入れると、登録済みのキーでは実行されません。

改善案として、長時間動作するアプリでは不要になったキーを削除するタイミングも決めておくとよいでしょう。本メソッドだけでは保存件数や有効期限を管理できません。まず完成コードの作成回数と登録数を確認し、実際の用途に合わせて保存期間を設計してください。

公式参考資料

PREFERRED SOURCES

Googleの優先するニュース提供元にSEの部屋を追加

Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。

Googleの設定画面で確認する 新しいタブで開きます

候補にSEの部屋が表示されない場合は、まだ追加できません。

y.
WRITTEN BY

y_ymo10

SEの部屋で、HTML・CSSからJavaScript・React・Next.jsまで、Web制作の開発ノートを公開しています。

ほかの開発ノートを読む →