凍結とシールの違い


164

JavaScriptメソッドfreezeとについて聞いたところseal、それを使用して任意のオブジェクトを不変にすることができます。

使用方法の簡単な例を次に示します。

var o1 = {}, o2 = {};
Object.freeze(o2);

o1["a"] = "worked";
o2["a"] = "worked";

alert(o1["a"]);   //prints "worked"
alert(o2["a"]);   //prints "undefined"

違いは何であるfreezeとはseal?彼らはパフォーマンスを向上させることができますか?


6
この質問を見ている人への単なるメモとして、受け入れられた答えは実際には正しくありません。@tungdの答えは正しいです。
ビョルン2014

2
もう1つの注意点として、Object.preventExtensionsとの他にもObject.sealありObject.freezeます。Object.preventExtensions新しいアイテムがオブジェクトに追加されないようにするだけです。で拡張性をオフにしたオブジェクトのプロパティの値を削除、構成、および変更できますObject.preventExtensions
ビョルン2014

回答:


193

Object.seal

  • 封印されたオブジェクトのプロパティの追加や削除を防ぎます。を使用deleteするとfalseが返されます
  • 既存のすべてのプロパティを構成不可能にします:それらは「データ記述子」から「アクセサー記述子」に(およびその逆に)変換できません。また、アクセサー記述子の属性はまったく変更できません(データ記述子はそのwritable属性を変更できますが、そのvalue属性writeableがtrueの場合)。
  • TypeError封印されたオブジェクト自体の値を変更しようとすると、(通常はstrictモードで)をスローできます

Object.freeze

  • 正確に何をするかObject.seal、さらに:
  • それは変更を防ぎます 任意の既存のプロパティを

どちらも「deep」/孫オブジェクトには影響しません。たとえば、objフリーズしている場合はobj.el再割り当てできませんが、obj.el変更できます(たとえば、obj.el.id変更できます)。


パフォーマンス:

オブジェクトをシールまたはフリーズすると、ブラウザによっては列挙速度に影響する場合があります。

  • Firefox:列挙のパフォーマンスは影響を受けません
  • IE:列挙型パフォーマンスへの影響は無視できる
  • Chrome:密封されたオブジェクトや凍結されたオブジェクトを使用すると、列挙のパフォーマンスが速くなります
  • Safari:封印または凍結されたオブジェクトの列挙が92%遅くなりました(2014年現在)

テスト:密封されたオブジェクト凍結されたオブジェクト


2
これらの方法を使用する理由についてお話しいただけますか?できるからって?
アラン・ドン

3
将来的には、ライブラリ/フレームワークを開発するときに、(適切に最適化されていれば)多く使用されると思います。これにより、ユーザーが(意図せずに)コードを壊すのを防ぐことができます(回答で述べたように、最適化により速度が大幅に向上するはずです)。しかし、これは純粋な憶測です:)
ニコロ・Campolungo

2
この回答には多くの事実上の誤りがあります。1つは、seal既存のプロパティを構成不可能にすることです。jsfiddle.net/ btipling / 6m743whnを参照してください番号2は引き続き編集できます。つまり、シールされたオブジェクトの既存のプロパティの値を変更します。
ビョルン2014

8
FWIW、凍結およびシールされたオブジェクトは、Chrome Canary v43.0.2317.0の凍結されていないシールされたオブジェクトよりも高速になりました。
llambda 2015

2
@AlanDong少し遅くなりますが、ここにオブジェクトをロックしたい理由があります。JavaScriptの機能の1つは、いつでもプロパティを追加できることです。あなたもこれを行うことができ、誤ってミスタイピングで。私の学生の多くは、呼び出されたイベントハンドラを追加しようとしたonClickonlick、それは働いていない理由を不思議に思っています。JavaScriptがエラーをスローする場合、それは間違いを犯すことの1つ少ないことです。次に、これにより、変更を防止するオブジェクトに定数プロパティを実装できます。これは、オブジェクトのメソッドで特に役立ちます。
Manngo 2017年

119

これら3つの方法を比較するテストプロジェクトを作成しました。

  • Object.freeze()
  • Object.seal()
  • Object.preventExtensions()

私の単体テストはCRUDケースをカバーしています:

  • [C]新しいプロパティを追加
  • [R]存在するプロパティを読み取る
  • [U]存在するプロパティを変更
  • [D]存在するプロパティを削除

結果:

ここに画像の説明を入力してください


2
これは素晴らしいです。UPDATEは、(definePropertyを介して)記述子属性の変更を考慮に入れていますか(構成可能、列挙可能、書き込み可能など)。
ドレナイ2017

DOMオブジェクトは(もちろん、ポリフィルの後)シールする必要があります。それは多くのタイプミスを防ぐのに役立ちます。
Manngo 2017年

@Manngo DOMオブジェクトをシールできます。DEBUGMODE変数を作成してに設定するだけtrueです。次に、行いますif (DEBUGMODE) { ... }。に...、すべてのDOMオブジェクトが常にシールされるようにする機能を配置します。次に、Webページスクリプトを配布する準備ができたら、に変更DEBUGMODEfalse、スクリプトをクロージャーコンパイラーで実行して配布します。それはそれと同じくらい簡単です。
ジャックギフィン2018

@JackGiffinコメントありがとうございます。私はいつもそれが良い考えだと思っていたとだけ言っていました。私は多くの学生がそのようなものを入力element.onlick=somethingし、それが機能しないためにイライラすることになりますが、技術的にはエラーではありません。
Manngo

2
@Lonelyでは、CRUDとは記述されません。あなたはRUDEのようなものに落ち着く必要があります;)
Manngo '

84

これらは常にMDNで検索できます。要するに:

  • Freeze:オブジェクトを不変にします。つまり、オブジェクトでない限り、定義されたプロパティの変更は許可されません。
  • シール:プロパティの追加を禁止しますが、定義されたプロパティは変更できます。

1
Object.seal()プロトタイプのプロパティも凍結しているよう
です

10

Object.freeze()は、凍結されたオブジェクトを作成します。つまり、既存のオブジェクトを受け取り、基本的Object.seal()にそれを呼び出しますが、すべての「データアクセサー」プロパティをとしてマークwritable:falseし、値を変更できないようにします。-カイル・シンプソン、JSを知らない-これとオブジェクトのプロトタイプ


4

ECMAScript 5のFreezeとSealの違いを見て、違いを明確にするスクリプトを作成しました。Frozenは、データと構造を含む不変オブジェクトを作成します。シールは、名前付きインターフェースの変更を防ぎます-追加、削除はできません-しかし、オブジェクトを変更して、そのインターフェースの意味を再定義できます。

function run()
{
    var myObject = function() 
    { 
        this.test = "testing"; 
    }

    //***************************SETUP****************************

    var frozenObj = new myObject();
    var sealedObj = new myObject();

    var allFrozen = Object.freeze(frozenObj);
    var allSealed = Object.seal(sealedObj);
    alert("frozenObj of myObject type now frozen - Property test= " + frozenObj.test);
    alert("sealedObj of myObject type now frozen - Property test= " + sealedObj.test);

    //***************************FROZEN****************************

    frozenObj.addedProperty = "added Property"; //ignores add
    alert("Frozen addedProperty= " + frozenObj.addedProperty);
    delete frozenObj.test; //ignores delete
    alert("Frozen so deleted property still exists= " + frozenObj.test);
    frozenObj.test = "Howdy"; //ignores update
    alert("Frozen ignores update to value= " + frozenObj.test);
    frozenObj.test = function() { return "function"; } //ignores
    alert("Frozen so ignores redefinition of value= " + frozenObj.test);

    alert("Is frozen " + Object.isFrozen(frozenObj));
    alert("Is sealed " + Object.isSealed(frozenObj));
    alert("Is extensible " + Object.isExtensible(frozenObj));

    alert("Cannot unfreeze");
    alert("result of freeze same as the original object: " + (frozenObj === allFrozen).toString());

    alert("Date.now = " + Date.now());

    //***************************SEALED****************************

    sealedObj.addedProperty = "added Property"; //ignores add
    alert("Sealed addedProperty= " + sealedObj.addedProperty);
    sealedObj.test = "Howdy"; //allows update
    alert("Sealed allows update to value unlike frozen= " + sealedObj.test);
    sealedObj.test = function() { return "function"; } //allows
    alert("Sealed allows redefinition of value unlike frozen= " + sealedObj.test);
    delete sealedObj.test; //ignores delete
    alert("Sealed so deleted property still exists= " + sealedObj.test);
    alert("Is frozen " + Object.isFrozen(sealedObj));
    alert("Is sealed " + Object.isSealed(sealedObj));
    alert("Is extensible " + Object.isExtensible(sealedObj));

    alert("Cannot unseal");
    alert("result of seal same as the original object: " + (sealedObj === allSealed).toString());

    alert("Date.now = " + Date.now());
}

3

少し遅れるかもしれませんが

  • 類似性:どちらも非拡張オブジェクトの作成に使用されます
  • 相違点:Freeze では 、オブジェクトの列挙可能な属性と書き込み可能な属性がに設定可能ですfalse。ここでは、シールされた 書き込み可能な属性が設定されてtrueおり、残りの属性はfalseです。

6
これは完全に正しいわけではありません。Object.getOwnPropertyDescriptor(Object.freeze({ prop: 1 }), 'prop').enumerable=== true
Leon Adler

2

オブジェクト全体をフリーズする代わりに、単一のオブジェクトプロパティを強制的にフリーズできるようになりました。これをパラメータとして使用するとObject.defineProperty、これを実現できwritable: falseます。

var obj = {
    "first": 1,
    "second": 2,
    "third": 3
};
Object.defineProperty(obj, "first", {
    writable: false,
    value: 99
});

この例でobj.firstは、値が99にロックされています。


0

以下の関数を比較し、これらの関数の違いを説明する簡単な表を作成しました。

  • Object.freeze()
  • Object.seal()
  • Object.preventExtensions()

上記の3つの方法の違いを説明する表

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.