Object.freeze() メソッドはオブジェクトを凍結します。凍結されたオブジェクトは変更できなくなります。オブジェクトを凍結すると、新しいプロパティを追加したり、既存のプロパティを削除したりすることができなくなり、既存のプロパティに対する列挙可否、構成可否、書き込み可否の変更ができなくなり、既存のプロパティの値が変更できなくなります。加えて、オブジェクトを凍結するとプロトタイプも変更できなくなります。 freeze() は渡されたものと同じオブジェクトを返します。

構文

Object.freeze(obj)

引数

obj
凍結するオブジェクトです。

返値

この関数に渡されたオブジェクトです。

説明

凍結されたオブジェクトにプロパティのセットを追加あるいは削除することはできません。実行しようとすると暗黙的あるいは TypeError エラーが発生して (もっとも一般的には strict mode において、ただしこれに限定はされません) 失敗します。

凍結されたオブジェクトデータプロパティについては、値を変更することはできず、構成可否、書き込み可否の属性は false に設定されます。アクセサープロパティ (ゲッターおよびセッター) は同様に動作します (そして、値を変更しているかのようにみえます)。なお、オブジェクトである値については、それも凍結されていない限り変更可能です。オブジェクトとして、配列は凍結可能です。凍結すると、要素が変更可能ではなくなり、配列に対する要素の追加や削除ができなくなります。

freeze() は関数に渡されたものと同じオブジェクトを返します。凍結されたコピーを生成する訳ではありません

オブジェクトの凍結

var obj = {
  prop: function() {},
  foo: 'bar'
};

// 新しいプロパティが追加でき、既存のプロパティは
// 変更や削除ができます
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;

// 渡されたオブジェクトと返されたオブジェクトはどちらも
// 凍結されています。元を凍結するために、返されたオブジェクトを
// 保存しておく必要がありません。
var o = Object.freeze(obj);

o === obj; // true
Object.isFrozen(obj); // === true

// すべての変更が失敗するようになりました
obj.foo = 'quux'; // 暗黙的に何も行われません
// 暗黙的にプロパティは追加されません
obj.quaxxor = 'the friendly duck';

// また、 strict モードではこれらの試みに対して TypeErrors が発生します
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 }

配列の凍結

let a = [0];
Object.freeze(a); // 配列が変更できなくなりました。

a[0]=1; // 暗黙に失敗
a.push(2); // 暗黙に失敗

// strict モードで試みると TypeError が発生します
function fail() {
  "use strict"
  a[0] = 1;
  a.push(2);
}

fail();

凍結されたオブジェクトは不変になります。しかし、定数であるとは限りません。以下の例では、凍結されたオブジェクトが定数ではないことを示しています (凍結が浅い)。

obj1 = {
  internal: {}
};

Object.freeze(obj1);
obj1.internal.a = 'aValue';

obj1.internal.a // 'aValue'

定数オブジェクトになるには、参照のつながり全体 (他のオブジェクトへの直接または間接的な参照) が不変で凍結されたオブジェクトのみを参照していなければなりません。凍結されるオブジェクトは、オブジェクト全体の中にあるオブジェクトの状態 (値と他のオブジェクトへの参照) がすべて固定されているので、不変ということができます。なお、文字列、数値、真偽値はすべて不変となり、関数や配列はオブジェクト扱いです。

浅い凍結とは

Object.freeze(object) を呼び出した結果は、 object の直属のプロパティにのみ適用され、 objectのみに対するその後のプロパティの追加、削除、値の再割り当て操作を禁止します。これらのプロパティの値がオブジェクトそのものであった場合、これらのオブジェクトは凍結されず、プロパティの追加、削除、値の再割り当て操作の対象になり得ます。

var employee = {
  name: "Mayank",
  designation: "Developer",
  address: {
    street: "Rohini",
    city: "Delhi"
  }
};

Object.freeze(employee);

employee.name = "Dummy"; // 非 strict モードでは暗黙に失敗
employee.address.city = "Noida"; // 子オブジェクトの属性は変更できる

console.log(employee.address.city) // 出力: "Noida"

オブジェクトを不変にするには、オブジェクト型のプロパティをそれぞれ再帰的に凍結させてください。 (深い凍結)。オブジェクトが参照グラフにUnknown prefix: 閉路.を含まないことが分かっている場合は、デザインパターンに基づいてケースバイケースのパターンを使用してください。そうでないと、無限ループが発生します。 deepFreeze() をパス (例えば配列) 引数を受け取る内部関数を持つよう拡張すると、オブジェクトを不変にするプロセスにいるときに、 deepFreeze() が再帰的に呼び出されることを防ぐことができます。凍結させてはいけない [window] のようなオブジェクトを凍結させる危険性がなおあります。

function deepFreeze(object) {

  // オブジェクトで定義されたプロパティ名を取得
  var propNames = Object.getOwnPropertyNames(object);

  // 自分自身を凍結する前にプロパティを凍結
  
  for (let name of propNames) {
    let value = object[name];

    object[name] = value && typeof value === "object" ? 
      deepFreeze(value) : value;
  }

  return Object.freeze(object);
}

var obj2 = {
  internal: {
    a: null
  }
};

deepFreeze(obj2);

obj2.internal.a = 'anotherValue'; // 非 strict モードでは暗黙に失敗
obj2.internal.a; // null

使用上のメモ

ECMAScript 5 では、このメソッドの引数がオブジェクト (プリミティブ) ではない場合、 TypeError が発生します。 ECMAScript 2015 では、オブジェクトではない引数は通常の凍結済みのオブジェクトである場合と同様に扱い、単純に返されます。

> Object.freeze(1)
TypeError: 1 is not an object // ES5 のコード

> Object.freeze(1)
1                             // ES2015 のコード

要素を伴う ArrayBufferView では、メモリ上のビューであり絶対的に他の問題の可能性があるため、 TypeError が発生します。

> Object.freeze(new Uint8Array(0)) // 要素梨
Uint8Array []

> Object.freeze(new Uint8Array(1)) // 要素あり
TypeError: Cannot freeze array buffer views with elements

> 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: Cannot freeze array buffer views with elements

なお、標準の三つのプロパティ (buf.byteLength, buf.byteOffset and buf.buffer) は読み取り専用ですので (ArrayBuffer または SharedArrayBuffer の場合)、これらのプロパティを凍結しようとする理由はありません。

Object.seal() との比較

Object.seal() によって封印されたオブジェクトは、既存のプロパティを変更することができます。 Object.freeze() によって凍結されたオブジェクトの既存のプロパティは、不変になります。

仕様書

仕様書 状態 備考
ECMAScript 5.1 (ECMA-262)
Object.freeze の定義
標準 初回定義。 JavaScript 1.8.5 で実装。
ECMAScript 2015 (6th Edition, ECMA-262)
Object.freeze の定義
標準  
ECMAScript Latest Draft (ECMA-262)
Object.freeze の定義
ドラフト  

ブラウザーの対応

Update compatibility data on GitHub
デスクトップモバイルサーバー
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOS 版 SafariSamsung InternetNode.js
基本対応Chrome 完全対応 6Edge 完全対応 ありFirefox 完全対応 4IE 完全対応 9Opera 完全対応 12Safari 完全対応 5.1WebView Android 完全対応 ありChrome Android 完全対応 ありEdge Mobile 完全対応 ありFirefox Android 完全対応 4Opera Android 完全対応 ありSafari iOS 完全対応 ありSamsung Internet Android 完全対応 ありnodejs 完全対応 あり

凡例

完全対応  
完全対応

関連情報

ドキュメントのタグと貢献者

このページの貢献者: mfuji09, teoli, ethertank, coeurl, yyss
最終更新者: mfuji09,