Javascript中冻结和密封的区别
我刚刚听说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"
这些方法有什么区别,它们可以提高性能吗?
Object.seal
- 它防止添加和/或删除密封对象的属性
- 尝试修改时可能会抛出
TypeError
(通常在严格模式下 ) - 使用
delete
将返回false - 它使每个属性都是不可configuration的,并且不能将其从数据访问器转换为属性(反之亦然)
Object.freeze
- 究竟是什么
Object.seal
,加上: - 它防止改变任何现有的属性
两者都不影响子对象(例如,如果obj
被冻结或封闭, obj.el
不能被改变,但是obj.el.id
可以)
至于性能,密封或冻结对象可以降低浏览器的枚举速度。
- Firefox:枚举性能不受影响
- IE:枚举性能影响可以忽略不计
- Chrome:枚举性能不受影响
- Safari:密封和冻结的对象枚举速度慢92%
testing: 密封的物体 , 冻结的物体 。
这很奇怪,因为密封和冻结应该允许引擎做一些强大的优化(对于冻结对象比密封对象更多),但是看起来,因为它们是“新”function,所以它们还没有被优化。 请把这个作为一个假设 ,因为我不知道在两种情况下他们的速度慢的原因。
您可以随时在MDN中查看这些信息。 简而言之:
- 冻结 :使对象不可变,意味着不允许改变定义的属性,除非它们是对象。
- 密封 :防止添加属性,但是定义的属性仍然可以改变。
我写了一个testing项目 ,比较这三种方法:
-
Object.freeze()
-
Object.seal()
-
Object.preventExtensions()
我的unit testing涵盖了CRUD的情况:
- [C]添加新的属性
- [R]读取已有的财产
- [U]修改已有的属性
- [D]删除存在的财产
结果:
Object.freeze()
创build一个冻结的对象,这意味着它需要一个现有的对象,本质上调用Object.seal()
,但它也标记所有的“数据访问器”属性为writable:false
,所以他们的值不能改变。 – 凯尔辛普森,你不知道JS – 这个&对象原型
我正在研究ECMAScript 5中Freeze和Seal之间的区别,并创build了一个脚本来阐明差异。 冻结创build一个不可变的对象,包括数据和结构。 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()); }
我知道我可能会迟到,但是
- 相似性:它们都用于创build不可扩展的对象 。
- 差异:在冻结可configuration,对象的可枚举和可写属性设置为
false
。 其中密封的可写属性设置为true
,其余属性为false。
现在可以强制冻结单个对象属性而不冻结整个对象。 你可以用Object.defineProperty
来实现这个Object.defineProperty
, writable: false
作为参数。
var obj = { "first": 1, "second": 2, "third": 3 }; Object.defineProperty(obj, "first", { writable: false, value: 99 });
在这个例子中, obj.first
现在将其值locking为99。