不变性

93 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第37天,点击查看活动详情

不变性

有时候我们可能希望对象或属性是不可变的,这里又有两种情况,深不变性和浅不变性。深不变性指的是不仅对象属性的特性不可变,如果对象属性是函数、数组等引用对象,也同样不可变,这样就使控制的难度加大了,是否必要值得商榷和重新理解。相反,浅不变性指的就是仅对象属性本身,不涉及到属性指向的对象或其他。

对于定义对象的不变性,常用的方法有:

对象常量

我们可以设置属性描述符writableconfigurablefalse,这样属性不可修改、重新定义并且不能被删除。

var myObject = {}
Object.defineProperty(myObject, 'NAME', {
  value: 100,
  writable: false,
  configurable: false
})

禁止扩展

如果你想要对象不可再添加任何新的属性,可以使用preventExtensions()方法。

var myObject = {
  a: 1
}
Object.preventExtensions(myObject)
myObject.a = 2
myObject.b = 3
console.log(myObject.a, myObject.b) // 2 undefined

preventExtensions()新增其他属性会静默失败,但修改原属性的值是可以的。说明只能在一定程度上限制对象的不可变性。

在严格模式下,新增属性会报错TypeError

封闭

Object.seal()封闭一个对象,不允许添加新的属性,并且对象属性的configurable描述符会被设为false,可写配置不变。

var myObject = {
  a: 1
}
Object.seal(myObject)
// configurable: false,enumerable: true,value: 1,writable: true
console.log(Object.getOwnPropertyDescriptor(myObject, 'a'))
myObject.b = 100
myObject.a = 2
console.log(myObject.a, myObject.b) // 2 undefined

封闭seal方法包含了preventExtensions方法不可扩展属性的功能,同时对属性的描述符功能也做了一定的限制。可以因场景使用。

冻结

Object.freeze()方法会冻结一个对象。先通过代码来看下不变性程度。

var myObject = {
  a: 1
}
Object.freeze(myObject)
// configurable: false,enumerable: true,value: 1,writable: false
console.log(Object.getOwnPropertyDescriptor(myObject, 'a'))
myObject.a = 2
console.log(myObject.a) // 1

freeze方法会改变对象属性的可配置和不可写配置,并且不能修改属性值。这个方法实际上是在现有对象上调用了seal方法,并把所有数据的可写属性设置为false,不可变程度比较高。