このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docsコミュニティーについてもっと知り、仲間になるにはこちらから。
Object.freeze()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2015年7月.
Object.freeze() は静的メソッドで、オブジェクトを凍結します。オブジェクトを凍結すると、拡張ができなくなり、既存のプロパティは書き込みも構成も不可能になります。新しいプロパティを追加したり、既存のプロパティを削除したり、列挙可能性、構成可能性、書き込み可能性、値を変更したり、オブジェクトのプロトタイプを再代入したりすることはできません。freeze() は、渡されたオブジェクトと同じものを返します。
オブジェクトの凍結は JavaScript が提供する最も高い完全性レベルです。
In this article
試してみましょう
const obj = { prop: 42,};Object.freeze(obj);obj.prop = 33;// 厳格モードではエラーが発生するconsole.log(obj.prop);// 予想される結果: 42構文
Object.freeze(obj)引数
obj凍結するオブジェクトです。
返値
この関数に渡されたオブジェクトです。
説明
オブジェクトを凍結することは、拡張を禁止し、既存のすべてのプロパティの記述子のconfigurable をfalse に変更すること、そしてデータプロパティについては、writable を同様にfalse に変更することと同じです。凍結したオブジェクトのプロパティ設定には、何も追加したり除去したりすることはできません。これを行おうとすると、静かに、あるいはTypeError 例外が発生し、失敗します(厳格モードの場合によく発生しますが、これに限ったことではありません)。
凍結されたオブジェクトのプロパティは、writable 属性とconfigurable 属性がfalse に設定されているため、値を変更することはできません。アクセサプロパティ(ゲッターとセッター)も同じように動作します。ゲッターによって返されるプロパティ値は変更される可能性があり、セッターはプロパティを設定する際にエラーを発生させることなく呼び出すことができます。オブジェクトである値は、凍結されていない限り変更することができることに注意してください。配列はオブジェクトとして凍結することができ、凍結後はその要素を変更したり、配列に要素を追加したり除去したりすることはできなくなります。
プライベート要素はプロパティではなく、プロパティ記述子の概念がありません。プライベート要素を持つオブジェクトを凍結しても、プライベート要素の値が変更されることはありません。(オブジェクトの凍結は通常、外部コードに対するセキュリティ対策として意味していますが、外部コードはいずれにせよプライベート要素にアクセスすることはできません。)オブジェクトが凍結されていてもいなくても、プライベート要素をオブジェクトに追加したり除去したりすることはできません。
freeze() は関数に渡されたものと同じオブジェクトを返します。凍結されたコピーを生成する訳ではありません。
要素を持つTypedArray やDataView はTypeError になります。これらはメモリー上のビューであり、他にも可能な問題を確実に引き起こします。
Object.freeze(new Uint8Array(0)); // 要素なし// Uint8Array []Object.freeze(new Uint8Array(1)); // 要素あり// TypeError: 要素を含む配列バッファービューは凍結できないObject.freeze(new DataView(new ArrayBuffer(32))); // 要素なし// DataView {}Object.freeze(new Float64Array(new ArrayBuffer(64), 63, 0)); // 要素なし// Float64Array []Object.freeze(new Float64Array(new ArrayBuffer(64), 32, 2)); // 要素あり// TypeError: 要素を含む配列バッファービューは凍結できないなお、標準の 3 つのプロパティ (buf.byteLength,buf.byteOffset,buf.buffer) は読み取り専用ですので(ArrayBuffer またはSharedArrayBuffer の場合)、これらのプロパティを凍結しようとする理由はありません。
Object.seal() とは異なり、Object.freeze() によって凍結されたオブジェクトの既存のプロパティは不変となり、データプロパティには代入できなくなります。
例
>オブジェクトの凍結
const obj = { prop() {}, foo: "bar",};// 凍結前: 新しいプロパティが追加でき、// 既存のプロパティは変更や削除ができますobj.foo = "baz";obj.lumpy = "woof";delete obj.prop;// 凍結const o = Object.freeze(obj);// 返値は渡したオブジェクトとまったく同じものです。o === obj; // true// オブジェクトは凍結されています。Object.isFrozen(obj); // === true// すべての変更が失敗するようになりましたobj.foo = "quux"; // 暗黙的に何も行われません// 暗黙的にプロパティは追加されませんobj.quaxxor = "the friendly duck";// また、厳格モードではこれらの試みに対して TypeError が発生しますfunction fail() { "use strict"; obj.foo = "sparky"; // TypeError が発生 delete obj.foo; // TypeError が発生 delete obj.quaxxor; // 属性 'quaxxor' が追加されたことがないため true を返す obj.sparky = "arf"; // TypeError が発生}fail();// Object.defineProperty から変更を試みますが、// 以下のどちらの文も TypeError が発生します。Object.defineProperty(obj, "ohai", { value: 17 });Object.defineProperty(obj, "foo", { value: "eit" });// プロトタイプを変更することもできず、// 以下のどちらの文も TypeError が発生します。Object.setPrototypeOf(obj, { x: 20 });obj.__proto__ = { x: 20 };配列の凍結
const a = [0];Object.freeze(a); // 配列が変更できなくなりました。a[0] = 1; // 暗黙に失敗// 厳格モードで試みると TypeError が発生しますfunction fail() { "use strict"; a[0] = 1;}fail();// push を試みるa.push(2); // TypeError が発生凍結されたオブジェクトは不変になります。しかし、定数であるとは限りません。以下の例では、凍結されたオブジェクトが定数ではないことを示しています(凍結が浅い)。
const obj1 = { internal: {},};Object.freeze(obj1);obj1.internal.a = "value";obj1.internal.a; // 'value'定数オブジェクトになるには、参照のつながり全体(他のオブジェクトへの直接または間接的な参照)が不変で凍結されたオブジェクトのみを参照していなければなりません。凍結されるオブジェクトは、オブジェクト全体の中にあるオブジェクトの状態(値と他のオブジェクトへの参照)がすべて固定されているので、不変ということができます。なお、文字列、数値、真偽値はすべて不変となり、関数や配列はオブジェクト扱いです。
深い凍結
Object.freeze(object) を呼び出した結果は、object の直属のプロパティにのみ適用され、object 上のみに対するその後のプロパティの追加、削除、値の再代入操作を禁止します。これらのプロパティの値がオブジェクトそのものであった場合、これらのオブジェクトは凍結されず、プロパティの追加、削除、値の再代入操作の対象になり得ます。
const employee = { name: "Mayank", designation: "Developer", address: { street: "Rohini", city: "Delhi", },};Object.freeze(employee);employee.name = "Dummy"; // 厳格モードでなければ暗黙に失敗employee.address.city = "Noida"; // 子オブジェクトの属性は変更できるconsole.log(employee.address.city); // 出力: "Noida"オブジェクトを不変にするには、オブジェクト型のプロパティをそれぞれ再帰的に凍結させてください(深い凍結)。オブジェクトが参照グラフに閉路を含まないことが分かっている場合は、デザインパターンに基づいてケースバイケースのパターンを使用してください。そうでないと、無限ループが発生します。例えば、function 構文で作成された関数は、prototype プロパティにその関数自身を指すコンストラクタープロパティがあるため、既定では循環参照が発生します。その他の関数(アロー関数など)は、それでも凍結することができます。
deepFreeze() をパス(例えば配列)引数を受け取る内部関数を持つよう拡張すると、オブジェクトを不変にするプロセスにいるときに、deepFreeze() が再帰的に呼び出されることを防ぐことができます。一例として、WeakSet を使用して循環参照を検出する方法をご覧ください。凍結させてはいけないwindow のようなオブジェクトを凍結させる危険性がなおあります。
function deepFreeze(object) { // オブジェクトで定義されたプロパティ名を取得 const propNames = Reflect.ownKeys(object); // 自分自身を凍結する前にプロパティを凍結 for (const name of propNames) { const value = object[name]; if ((value && typeof value === "object") || typeof value === "function") { deepFreeze(value); } } return Object.freeze(object);}const obj2 = { internal: { a: null, },};deepFreeze(obj2);obj2.internal.a = "anotherValue"; // 厳格モードでなければ暗黙に失敗obj2.internal.a; // null仕様書
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-object.freeze> |