对象密闭的四种方式
对象密闭是比较常见的业务需求,对象密闭可以防止属性被篡改,减少出错几率。
下面介绍常见的4种使对象密闭的方式。
1. Object.defineProperty()
定义对象属性,属性不可删除、不可修改,可以添加属性,不能禁止对象拓展。
let obj = { a: 1 };
Object.defineProperty(obj, 'a', {
configurable: false,
writable: false
});
obj.a = 2;
obj.b = 2;
delete obj.a;
console.log(obj); // { a: 1, b: 2 }
从案例来看,对象是不可删除、不可修改的,但是可以添加属性。
Object.defineProperty()定义的属性,属性描述符都是false。
通过对象点语法添加属性,属性描述符都是true。
2. Object.preventExtensions()
禁止对象拓展,不能添加属性,原有属性可以删除和修改。
Object.isExtensible():查看对象是否可拓展。true为可拓展,false为不可拓展。
let obj = { a: 1 };
console.log(Object.isExtensible(obj)); // true
Object.preventExtensions(obj);
console.log(Object.isExtensible(obj)); // false
obj.b = 2;
obj.a = 3;
console.log(obj); // { a: 3 }
delete obj.a;
console.log(obj); // { }
从案例来看,对象不能添加属性,但是可以修改原有属性,也可以删除原有属性。
非严格模式下,对设置不可拓展的对象新增属性,会静默失败。
严格模式下,如果对其新增属性,会报错。错误如下。
TypeError: Cannot add property b, object is not extens
3. Object.seal()
对象密封,对象不可拓展,不可删除,原有属性可修改。
Object.seal()本质就是调用Object.preventExtensions()方法,并将属性的configurable设置为false。
Object.isSealed():查看对象是否密封。false代表未密封,true代表已密封。
let obj = { a: 1 };
console.log(Object.isSealed(obj)); // false
Object.seal(obj);
console.log(Object.isSealed(obj)); // true
obj.b = 3;
obj.a = 2;
console.log(obj); // { a: 2 }
delete obj.a;
console.log(obj); // { a: 2 }
从案例可以看出,对象不能添加属性,不能删除属性,但是可以修改原有属性。
非严格模式下,添加属性和删除属性会静默失败。严格模式下,会报错。
4. Object.freeze()
对象冻结,对象不可拓展、不可删除、不可修改。并没有深度冻结。
Object.isFrozen():查看对象是否冻结。false代表未冻结,true代表已被冻结。
let obj = { a: 1 };
console.log(Object.isFrozen(obj)); // false
Object.freeze(obj);
console.log(Object.isFrozen(obj)); // true
obj.a = 2;
obj.b = 3;
console.log(obj); // { a: 1 }
delete obj.a;
console.log(obj); // { a: 1 }
从案例来看,对象不可拓展,不可删除,不可修改。
非严格模式下,操作冻结的对象会静默失败。严格模式下,会报错。
const person = {
name: 'zhangsan',
son: {
name: 'lisi',
son: {
name: 'wangwu'
}
}
};
Object.freeze(person);
person.name = 'zhangsan2';
person.son.name = 'lisi2';
console.log(person);
// { name: 'zhangsan', son: { name: 'lisi2', son: { name: 'wangwu' } } }
从案例来看,Object.freeze()不能进行深度冻结,person.son.name已经被修改。
自定义freeze函数(不常用)
循环判断属性是否是object,如果是object,冻结处理,并递归判断其属性。
通过typeof判断是否为object,注意typeof(null)也是object,需要排除掉此项。
/**
* 对象冻结
*
* @param {*} obj
*/
function freeze (obj) {
Object.freeze(obj);
for (const key in obj) {
if (typeof(obj[key]) === 'object' && obj[key] !== null) {
freeze(obj[key]);
}
}
}
const person = {
name: 'zhangsan',
son: {
name: 'lisi',
son: {
name: 'wangwu'
}
}
};
freeze(person);
person.name = 'zhangsan2';
person.son.name = 'lisi2';
console.log(person);
// { name: 'zhangsan', son: { name: 'lisi', son: { name: 'wangwu' } } }
通过案例可以看出,person.son.name并没有被修改,实现对象的深度冻结。