😄 从Object.defineProperty说起
使用Object.defineProperty可以给对象定义属性,同时可以给当前属性定义是否可配置,可写,可枚举等特性。比如
const a = {}
Object.defineProperty(a, "p", {
value: 123,
configurable: true,
writable:true,
enumerable: true
})
上面的代码给对象a定义了一个p属性,同时通过data descriptor定了特性。这里主要关注两个描述符字段:configurable和writable。
configurable:可配置,表示属性是否可以删除,或者重新配置当前data descriptor的值writable:可写,表示是否可以给属性重新赋值
😄 Object.preventExtensions
Object.preventExtensions是防止对象新增属性,也防止对象的原型被重新赋值。
const o1 = {};
Object.preventExtensions(o1);
try {
Object.defineProperty(o1, 'p1', {
value: 111
});
} catch (e) {
console.log(e);
// TypeError: Cannot define property p1, object is not extensible
}
这里可以看到,如果给o1添加新的属性p1就会报object is not extensible的错误,此时o1不可扩展。
可以通过Object.isExtensible()来判断是否被prevent
Object.isExtensible(o1) // true
😁 Object.seal
Object.seal的效果相当于: 在Object.defineProperty时将configurable设置成false,同时对对象调用Object.preventExtensions。但是原有的属性值是可以修改的。
(function(){
// 必须在严格模式下 才有产生error 否则 静默失败
"use strict";
const o2 = { p2: "hello world" }
Object.seal(o2)
try {
delete o2.p2
} catch (e) {
console.log(e) // Cannot delete property 'p2' of #<Object>
}
try {
o2.p3 = 'p3' // Cannot add property p3, object is not extensible
} catch (e) {
console.log(e)
}
o2.p2 = 'newValue' // 修改成功
// 此时的 o2 { p2: "newValue" }
})()
必须在严格模式下才会报错, 否则只是静默失败
可以通过Object.isSealed()来判断是否被seal
😆 Object.freeze
Object.freeze是在Object.seal的基础上再防止属性值被修改,将属性都变成 只读型(Readonly)。
如果重新在运行上面的代码,会发现 o2.p2 = 'newValue'也会产生错误:
(function(){
// 必须在严格模式下 才有产生error 否则 静默失败
"use strict";
const o2 = { p2: "hello world" }
Object.seal(o2)
try {
delete o2.p2
} catch (e) {
console.log(e) // Cannot delete property 'p2' of #<Object>
}
try {
o2.p3 = 'p3'
} catch (e) {
console.log(e) // Cannot add property p3, object is not extensible
}
try {
o2.p2 = 'newValue' // 修改失败
} catch (e) {
console.log(e) // Cannot assign to read only property 'p2' of object '#<Object>
}
// 此时的 o2 { p2: "hello world" }
})()
可以使用Object.isFrozen来判断是否被freeze
🤩 Object.preventExtensions vs Object.seal vs Object.freeze
从上面可以看出,这三个方法对 对象的保护程度 是依次递增的。
Object.preventExtensions只防止添加属性,不可扩展Object.seal除了不可扩展,也不可配置Object.freeze就像freeze的意思是被冻结,不可扩展,不可配置,不可重写。
同时他们还有一个共同特点: 他们的这种保护机制只能针对自身属性,无法深度freeze:
var obj = { a: { b: { c: 123 } } }
Object.freeze(obj)
delete obj.a // false
// 无法 深度freeze
Object.isFrozen(obj.a.b) // false
Object.isFrozen(obj.a) // false
delete obj.a.b.c // true
delete obj.a.b // true