Object.freeze() 和 Object.seal()
Aix Trainee

首先定义一个对象:

1
2
3
4
5
const obj = {
name: 'xt',
}
obj.name = 'bb'
console.log(obj) // {name: 'bb'}

虽然这里使用了 const 关键字,其实创建的只是一个对象引用,所以依旧是可以修改对象里面的值的,如果我们想让对象不可以修改,应该怎么办呢?
那就要用到 Object.freeze()了。它的作用是冻结一个对象,被冻结的对象再也不能被修改,不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

1
2
3
4
const arr = [1, 2, 3]
Object.freeze(arr)
arr[0] = 11
console.log(arr) // [1,2,3]

可以看到对象被“冻结”了,传入一个数组看看:

1
2
3
4
const arr = [1, 2, 3]
Object.freeze(arr)
arr[0] = 11
console.log(arr) // [1,2,3]

可以发现 freeze() 同样可以使数组冻结,这其实也很好理解,数组本质也是对象嘛。

1
2
3
4
5
6
7
8
9
const obj = {
name: 'xt',
props: {
num: 1,
},
}
Object.freeze(obj)
obj.props.num = 2
console.log(obj.props.num) // 2

这里我们可以发现一个问题,当对象里其他引用类型的时候,冻结效果失效了。。。这让我想到了浅拷贝,那是不是可以类似“深拷贝”一样,也来封装一个“深冻结”,尝试一下看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const deepFreeze = object => {
for (const key in object) {
const element = object[key]
if (Object.hasOwnProperty.call(object, key) && element && typeof element === 'object') {
deepFreeze(element)
}
}
return Object.freeze(object)
}
const obj = {
name: 'xt',
props: {
num: 1,
},
}
deepFreeze(obj)
obj.props.num = 2
console.log(obj.props.num) // 1

emm 果然不出所料,成功做到了“深冻结”。
原理:如果知道 Object.defineProperty(),通过下面的属性就可以做到冻结的效果

1
2
3
4
5
6
7
8
9
const obj = {}
Object.defineProperty(obj, 'name', {
enumerable: false, // 表示是否可以枚举。默认值false
writable: false, // 表示能否修改属性的值,即值是可写的还是只读。默认值false
configurable: false, // 表示能否通过 delete 删除属性、能否修改属性的特性。默认值false
value: 'xt', // 属性的值
})
obj.name = 'bb'
console.log(obj.name) // xt

有时候我们想保持原来的数据结构,又改变对象里面的值,怎么办呢?这就可以用 Object.seal()

1
2
3
4
5
6
7
8
9
const obj = {
name: 'xt',
age: 2,
}
Object.seal(obj)
obj.age = 20
console.log(obj.age) // 20
delete obj.age
console.log(obj.age) // 20

可以看到能够修改属性,但是删除不了。
Object.freeze()和 Object.freeze()的区别就是前者允许修改属性,而后者则不可以。

 评论