一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
在面向对象和函数式编程中,不可变对象其状态在创建后无法修改的对象。这与可变对象形成对比,可变对象创建后可以修改。
在某些情况下,即使某些内部使用的属性发生变化,对象也被认为是不可变的,但从外部角度来看,对象的状态似乎没有变化。
字符串和其他具体对象通常表示为不可变对象,以提高面向对象编程的可读性和运行时效率。不可变对象也很有用,因为它们本质上是线程安全的。其他好处是它们比可变对象更易于理解和推理,并提供更高的安全性。
在JavaScript中,所有原始类型(Undefined、Null、Boolean、Number、BigInt、String、Symbol
)都是不可变的,但自定义对象通常是可变的。
我们可以通过使用freeze()
和seal()
方法来实现不可变对象。
JavaScript 中创建对象并将其分配给变量时,它不保存对象的值。这个变量只有对我们创建的对象的引用。
例如,如果我们创建一个对象poi,将其分配给另一个变量 pubPoi,我们将复制poi的引用,而不是值。因此,如果我们对pubPoi进行更改,也会修改poi值。
示例如下:
var poi = {
name: "hotel",
address: "beijing",
};
var pubPoi= poi;
pubPoi.name = "scenic";
console.log(poi);
复制代码
Object.freeze()
Object.freeze()
方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。
此外,冻结一个对象后该对象的原型也不能被修改。freeze()
返回和传入的参数相同的对象。
示例如下:
var poi = {
name: "hotel",
address: "beijing",
};
Object.freeze(poi);
poi.name = "test";
// Throws an error in strict mode
console.log(poi.name);
// expected output: hotel
复制代码
注意:
1.Object.freeze()
方法不会影响嵌套对象,如果需要冻结嵌套对象并使其不可变,则需要遵循递归方法逐级冻结。
2.Object.isFrozen()
方法可以判断一个对象是否被冻结。
Object.seal()
Object.seal()
是另一种使对象不可变的方法。但是,它和 freeze()
有点不同。Object.seal()
仅保护对象不添加和删除属性。它允许更新现有属性。
var poi = {
name: "hotel",
address: "beijing",
};
// 冻结
Object.seal(poi);
// 添加属性
poi["state"] = 0;
// 删除属性
delete poi["name"];
// 更新属性
poi.name = "scenic";
console.log(poi);
复制代码
对象添加和删除属性失败。但是,名称属性可以更新。
注意:
1.可以使用 isSealed()
方法来确认对象的密封状态。
2.Object.seal()
还具有类似于 Object.freeze()
的浅密封行为。所以需要一个递归策略来密封嵌套对象。
3.除了这2个方法之外,我们还可以使用Object.preventExtensions()
方法,只防止向对象添加新的属性。
const 关键字不会使对象不可变
使用 const
关键字创建对象时,它只会阻止我们重新分配值。但是,我们可以更新、添加和删除创建的对象的属性。
const poi = {
name: "hotel",
address: "beijing",
};
poi.name = "scenic";
delete poi["address"];
poi["state"] = 0;
console.log(poi);
复制代码
const
关键字只提供了赋值的不变性。它并不提供值的不可更改性。