JavaScript 中 freeze 和 seal 的区别有那些

我刚刚听说了JavaScript方法freezeseal,它们可以用来使任何对象不可变。

下面是一个如何使用它的简短例子:

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


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


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

freezeseal之间的区别是什么?它们能提高性能吗?

47767 次浏览

你可以在MDN中找到这些。简而言之:

  • 冻结:使对象不可变,这意味着不允许更改已定义的属性,除非它们是对象。
  • 密封:防止添加属性,但是已定义的属性仍然可以更改。

Object.seal

  • 它防止从密封对象中添加和/或删除属性;使用delete将返回false
  • 它使得每个现有的属性不可配置:它们不能从“数据描述符”转换为“访问器描述符”(反之亦然),而且访问器描述符的任何属性都不能被修改(而数据描述符可以改变它们的writable属性,如果writeable为真,则可以改变它们的value属性)。
  • 可以在尝试修改密封对象本身的值时抛出TypeError(最常见的是在严格模式中)

Object.freeze

  • 正是Object.seal所做的,加上:
  • 它阻止修改任何现有属性

两者都不影响“深”/孙辈对象。例如,如果obj被冻结,obj.el不能被重新分配,但是obj.el的值可以被修改,例如obj.el.id可以被改变。


性能:

密封或冻结一个对象可能会影响它的枚举速度,这取决于浏览器:

  • Firefox:枚举性能不受影响
  • IE:枚举性能影响可以忽略不计
  • 铬:枚举性能更快与密封或冻结的对象
  • Safari:密封或冻结对象枚举速度慢92%(截至2014年)

测试:密封的对象冻结对象

Object.freeze()创建一个冻结对象,这意味着它接受一个 对象,本质上调用Object.seal(),但它还将所有“数据访问器”属性标记为writable:false,因此它们的值不能被更改

——凯尔·辛普森《你不知道JS》对象的原型

我查看了ECMAScript 5中Freeze和Seal之间的差异,并创建了一个脚本来澄清这些差异。Frozen创建一个包含数据和结构的不可变对象。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());
}

我知道我可能会晚一点,但是

    相似之处:它们都用于创建非可扩展 李对象> < /强劲。< / >
  • 区别:在Freeze 可配置,可枚举和可写 对象的属性被设置为false。如密封 可写的属性被设置为true,其余属性为false。

您现在可以强制冻结单个对象属性,而不是冻结整个对象。你可以用Object.definePropertywritable: false作为参数来实现这一点。

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

在本例中,obj.first现在将其值锁定为99。

我写了一个测试项目来比较这3个方法:

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

我的单元测试涵盖了CRUD案例:

  • [C]添加新属性
  • [R]读已有的财产
  • [U]修改已有的财产
  • [D]移除存在的财产

结果:

enter image description here

我创建了一个简单的表来比较下面的函数,并解释这些函数之间的区别。

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

table that explanation the difference between above三种方法 . b

我在我的开源电子书里写过这个。它有一个关于对象限制https://github.com/carltheperson/advanced-js-objects/blob/main/chapters/chapter-3.md#object-restrictions的部分

总结:

这个表显示了限制的层次结构: Table of restrictions < / p >

Object.preventExtensions失败的例子

const obj = { a: "A", b: "B" }
Object.preventExtensions(obj)


obj.c = "C" // Failure


console.log(obj) // { a: "A", b: "B" }

Object.seal失败的例子

const obj = { a: "A", b: "B" }
Object.seal(obj)


delete obj.a // Failure
obj.c = "C" // Failure


console.log(obj) // { a: "A", b: "B" }

Object.freeze失败的例子

const obj = { a: "A", b: "B" }
Object.freeze(obj)


delete obj.a // Failure
obj.b = "B2" // Failure
obj.c = "C" // Failure


console.log(obj) // { a: "A", b: "B" }

注意:他们如何“失败”;取决于你的代码是否在严格模式下运行。

  • 严格模式=错误
  • 非严格模式=无声失败