2014-01-28 49 views
98

我剛剛聽說JavaScript方法freezeseal,它們可以用來使任何Object不可變。Javascript中凍結與封印的區別

這裏是一個簡短的例子,如何使用它:

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

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

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

是什麼這些方法之間的差異,他們可以提高性能?

+0

什麼是'lock'? –

+0

@LightStyle我誤解了文章。沒有'鎖定'功能,他們只說'凍結'和'密封'用於鎖定。 – maja

+4

只要給任何人看這個問題的提示,接受的答案是事實不正確的。 @ tungd的回答是正確的。 –

回答

117

Object.seal

  • 它防止添加和/或從密封對象
  • 除去的屬性(在嚴格模式最常用)
  • 當試圖修改使用delete可以拋出TypeError將返回錯誤
  • 它使每個屬性都不可配置,並且它們不能從數據訪問轉換ORS對屬性(反之亦然)

Object.freeze

  • 究竟是什麼Object.seal呢,再加上:
  • 它可以防止改變任何現有的屬性

無論是一個影響到子對象(例如如果obj被凍結或密封,obj.el不能更改,但obj.el.id可以)

對於性能,密封或凍結對象可以降低其瀏覽器的枚舉速度。

  • 火狐:枚舉性能不受影響
  • IE:枚舉性能的影響是可以忽略的
  • 鉻:枚舉性能不受影響
  • Safari中:密封並凍結對象枚舉慢92%

測試:Sealed objectsFrozen objects

這很奇怪,因爲密封和凍結應該允許引擎做一些強大的優化(對凍結的對象比密封的對象更多),但似乎是因爲它們是「新」功能,所以它們還沒有優化了。請參考假設,因爲我不知道他們在這兩種情況下速度如此之慢的原因。

+2

您可以談談爲什麼我們會使用這些方法嗎?只因爲我們可以嗎? –

+2

未來,我認爲在開發一個庫/框架時,它們會被大量使用(如果正確優化)。它們允許您防止用戶(甚至無意中)破壞您的代碼(並且,正如答案中所述,優化應該會帶來巨大的速度提升)。但這是純粹的猜測:) –

+1

這個答案有很多事實錯誤。首先,'seal'也使現有屬性不可配置,請參閱http://jsfiddle.net/btipling/6m743whn/ Number 2,您仍然可以編輯,即更改密封對象上現有屬性的值。 –

74

您可以隨時在MDN中查看這些信息。總之:

  • Freeze:使對象不可變,這意味着沒有改變定義的屬性允許,除非它們是對象。
  • Seal:防止添加屬性,但是定義的屬性仍然可以更改。
+0

'Object.seal()'似乎也凍結了原型屬性:\ –

7

Object.freeze()創建一個凍結的對象,這意味着它需要一個 現有對象和基本要求就可以了Object.seal(),但它也 標記所有「數據訪問」屬性writable:false,使他們的 值不能改變。 - 凱爾辛普森,你不知道JS - 這&對象原型

3

我在看ECMAScript 5中凍結和密封之間的差異,並創建了一個腳本來闡明差異。凍結創建一個包含數據和結構的不可變對象。 Seal可以防止對命名接口的更改 - 不會添加,刪除 - 但是您可以改變對象並重新定義接口的含義。

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()); 
} 
1

我知道我可能會遲到一點,但

  • 相似:兩者都被用於創建不可延展 對象
  • 差異:在凍結對象的配置的,枚舉的和可寫的 屬性設置爲false。如在密封中 可寫屬性設置爲true,其餘屬性爲假。
+1

這不完全正確。 Object.getOwnPropertyDescriptor(Object.freeze({prop:1}),'prop')。enumerable' ==='true'。 –

0

您現在可以強制凍結單個對象屬性,而不凍結整個對象。您可以通過Object.definePropertywritable: false作爲參數來實現此目的。

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

在這個例子中,obj.first現已其值鎖定到99

21

我寫了test project這些3種方法比較:

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

我的單元測試覆蓋CRUD情況:

  • [C]添加新的屬性
  • [R]讀取存在屬性
  • [U]修改存在屬性
  • [d]移除存在屬性

結果:

enter image description here

+0

這太棒了。 UPDATE是否考慮了修改(通過defineProperty)描述符屬性,例如可配置,可枚舉,可寫? – Ryan

+0

我始終認爲DOM對象應該被密封(當然是在polyfills之後)。這將有助於防止大量的拼寫錯誤。 – Manngo

+0

也許「EXTEND」而不是「CREATE」在這方面會更具表現力,.. – Lonely