JavaScript

JavaScriptのObject.isFrozen():設定オブジェクトが凍結済みか確認する

この記事でわかること

Object.isFrozen()でオブジェクトの凍結状態を確認する方法を解説。引数・戻り値、ブラウザーとNode.jsの実行手順、期待出力、入れ子やアクセサーを判定する際の制約を学べます。

目的:変更できない設定を受け取ったか確認する

共通の設定オブジェクトを複数の処理へ渡すとき、「この設定は呼び出し先で書き換えられない」という前提を置くことがあります。その前提を実行時に確かめる関数がObject.isFrozen()です。

この関数は対象の凍結状態を調べ、真偽値を返します。対象を凍結する処理は行いません。設定を作る側と使う側が分かれているコードで、受け渡しの契約を点検するために使えます。基本仕様はMDNのObject.isFrozen()に記載されています。

ただし、戻り値がtrueでも、内部のすべての値が永久に変わらないとは限りません。本記事では普通のオブジェクトを使い、判定できる範囲を確認します。

動作環境とバージョン

Object.isFrozen()はECMAScript 5で導入された標準の静的メソッドです。ブラウザー専用のAPIではないため、ブラウザーとNode.jsの両方で利用できます。

2026年11月14日時点で確認したMDNでは、2015年7月以降、ブラウザー間で広く利用できる機能とされています。現在のChrome、Edge、Firefox、Safariで使用する場合、追加ライブラリーは不要です。ただし、この年月は各ブラウザーの初回実装日を表すものではありません。MDNの対応状況を参照してください。

本文のコードはNode.js 22系・24系でも実行できる標準JavaScriptだけで構成しています。DOM、外部通信、パッケージの読み込みは使いません。ここで挙げたバージョンは実行対象であり、機能が初めて導入されたNode.jsのバージョンではありません。Node.jsと標準言語機能の関係はNode.jsのECMAScript解説で確認できます。

古い実装との違い

オブジェクト以外を渡した場合の仕様は変更されています。ES5では例外でしたが、ES2015以降はtrueを返します。したがって、trueという結果だけで「設定用のオブジェクトが渡された」とは判断できません。入力の型も別に確認します。

引数・戻り値と判定条件

呼び出し形式は次のとおりです。

JavaScript
Object.isFrozen(value);
  • 引数のvalueは、凍結状態を確認したい値です。
  • 戻り値はboolean型のtrueまたはfalseです。
  • 対象を変更せず、同期的に結果を返します。Promiseやawaitは使いません。

普通のオブジェクトでは、プロパティを追加できず、既存の自身のプロパティを再構成できず、データプロパティを書き換えられない状態でtrueになります。アクセサープロパティはデータプロパティと扱いが異なります。MDNの判定条件が根拠です。

ここで調べるのは、現在の状態です。「過去に凍結用の関数が呼ばれたか」という履歴を記録する仕組みではありません。また、親オブジェクトから参照している子オブジェクトまで再帰的に検査する機能もありません。

コピーして試す:設定の受け渡しを点検する

次のコード全体を使ってください。Object.freeze()は比較用の凍結済みデータを作るために使い、確認の中心はObject.isFrozen()です。

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

  if (typeof Object.isFrozen !== "function") {
    console.log("この環境はObject.isFrozen()に未対応です");
    return;
  }

  function requireFrozenSettings(value) {
    if (
      value === null ||
      typeof value !== "object" ||
      Array.isArray(value)
    ) {
      throw new TypeError("設定にはオブジェクトを渡してください");
    }

    if (!Object.isFrozen(value)) {
      throw new TypeError("設定が凍結されていません");
    }

    return value;
  }

  const draft = { retries: 2 };
  const settings = Object.freeze({
    retries: 2,
    ui: { theme: "light" }
  });

  console.log(`draft: ${Object.isFrozen(draft)}`);
  console.log(`settings: ${Object.isFrozen(settings)}`);
  console.log(`ui: ${Object.isFrozen(settings.ui)}`);

  const accepted = requireFrozenSettings(settings);
  console.log(`同じ参照: ${accepted === settings}`);

  try {
    requireFrozenSettings(draft);
  } catch (error) {
    console.log(`受付失敗: ${error.message}`);
  }

  try {
    settings.retries = 3;
  } catch (error) {
    console.log(`書き換え失敗: ${error.name}`);
  }

  settings.ui.theme = "dark";
  console.log(`theme: ${settings.ui.theme}`);
  console.log(`親の判定: ${Object.isFrozen(settings)}`);
})();

ブラウザーでの実行方法

開発者ツールのConsoleを開き、コード全体を貼り付けて実行します。ページ内の要素には依存しません。即時実行関数で囲んでいるため、同じConsoleで再実行しても、トップレベルの変数宣言が衝突しにくい構成です。

Node.jsでの実行方法

Node.jsを導入した環境で、コード全体をUTF-8のcheck-frozen.cjsとして保存します。そのファイルがあるディレクトリーで、次を実行します。.cjsを使うことで、周辺のプロジェクトのモジュール設定に左右されずに試せます。

Shell
node --version
node check-frozen.cjs

ファイル名をnodeに渡す実行方法はNode.js公式の実行手順に基づきます。

期待出力と読み方

対応環境では、次の順序の出力を想定しています。これはコードと仕様から確認した期待値であり、実機での実行結果ではありません。

CODE
draft: false
settings: true
ui: false
同じ参照: true
受付失敗: 設定が凍結されていません
書き換え失敗: TypeError
theme: dark
親の判定: true

requireFrozenSettings()は条件を満たした引数をそのまま返すため、コピーは作りません。凍結されていないdraftは例外で拒否します。settings.retriesへの代入はstrictモードで失敗しますが、catchで処理するため、その後も実行が続きます。

一方、settings.uiは凍結されていません。子のthemeを変更しても、親の凍結状態は変わらないので、最後の判定もtrueです。浅い凍結とstrictモードの動作はMDNのObject.freeze()に説明があります。

失敗例と制約を理解する

プリミティブを設定として受理してしまう

現代の環境では、次の判定はすべてtrueになります。

JavaScript
console.log(Object.isFrozen(42));
console.log(Object.isFrozen(null));
console.log(Object.isFrozen(undefined));
CODE
true
true
true

これらは設定オブジェクトとして適切かどうかとは別の話です。主例でnullと型を先に調べたのは、この取り違えを防ぐためです。なお、主例の入力確認は設定項目の存在や値の範囲までは検証していません。

アクセサーの結果まで固定されると思ってしまう

凍結されていても、getterが返す値は外部の状態に応じて変化できます。次の例も単独で実行できます。

JavaScript
(() => {
  let current = 1;
  const status = Object.freeze({
    get count() {
      return current;
    }
  });

  console.log(Object.isFrozen(status));
  console.log(status.count);
  current = 2;
  console.log(status.count);
})();
CODE
true
1
2

countというプロパティの構成が固定されていても、getterが読む変数まで固定されるわけではありません。setterも呼び出せる場合があります。この制約はMDNのアクセサーに関する説明に沿ったものです。

活用事例と導入時の改善案

実務では、設定ファクトリーが返した値の検査や、共有定数を渡す直前の開発用チェックに向いています。「想定した凍結状態になっているか」を境界で調べれば、作成側の処理漏れを早く発見できます。

ただし、凍結判定を業務上の入力検証の代わりに使うのは避けます。たとえばretriesに文字列が入っていても、凍結されていれば判定は通ります。設定の安全性が必要なら、型・必須項目・数値範囲の検証を先に行い、凍結状態の検査を追加する順序が現実的です。

改善案として、変更禁止の設定は、まず文字列・数値・真偽値中心の平坦な構造にすると扱いやすくなります。親だけを調べて子も固定済みだと誤解する余地が減るためです。入れ子が必要なら、どの階層の変更を禁止するかを設計し、その階層を個別に確認してください。

公式参考資料

  • MDN:Object.freeze()は、凍結後の代入、入れ子、アクセサーの制約を確認する資料です。
PREFERRED SOURCES

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

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

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

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

y.
WRITTEN BY

y_ymo10

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

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