小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
冻结对象 - Object.freeze()
Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。(以上来自MDN的解释)
增删查改
上面概念讲那么多,无非就是围绕着对一个对象,我们冻结之后,是否能对其进行增删查改的属性操作。
// 增删查改
var obj = {
name: '橙某人'
};
Object.freeze(obj);
/**********本身属性**********/
// 增
obj.age = 18;
console.log(obj); // {name: "橙某人"}
// 删
delete obj.name;
console.log(obj); // {name: "橙某人"}
// 查
console.log(obj.name); // 橙某人
// 改
obj.name = 'yd';
console.log(obj); // {name: "橙某人"}
/**********原型属性**********/
// 增 (删查改也可以, 就不写了)
obj.__proto__.age = 18;
console.log(obj); // {name: "橙某人", [[Prototype]]: {age: 18}};
// 覆盖整个原型对象
obj.__proto__ = {}; // 报错: Uncaught TypeError: #<Object> is not extensible
结论:被冻结的对象,无法对本身属性进行增删改,只能查;而对象的原型对象如常,只是不能直接进行覆盖整个原型对象的操作。
返回值
// ES6 环境
var obj = {
name: '橙某人'
};
var o = Object.freeze(obj);
console.log(obj === o); // true
console.log(Object.freeze(123)); // 123
console.log(Object.freeze('123')); // '123'
console.log(Object.freeze(true)); // true
console.log(Object.freeze(() => {})); // () => {}
结论:
Object.freeze()方法在ES6以上环境返回值为被冻结的对象;但是在ES5环境下,参数不是对象的会直接报错。
(可以随便找一个低版本IE浏览器跑一下)
浅冻结
何为浅冻结?这和浅拷贝是差不多的意思,一般涉及对象的操作,我们都应该要本能的考虑到对象里面镶嵌对象可能会带来的问题。
var obj = {
name: {
nickname: '橙某人'
}
};
var o = Object.freeze(obj);
obj.name.nickname = 'yd';
console.log(obj); // {name: {nickname: 'yd'}}
obj.name.nickname = 'YD';
console.log(obj); // {name: {nickname: 'YD'}}
delete obj.name.nickname;
console.log(obj); // {name: {}}
结论:被冻结的对象,只有第一层会被冻结,深层次的属性依旧如常,能正常增删查改。
深冻结
既然上面提到了 Object.freeze() 方法只是浅冻结,那么我们要实现完全冻结一个完整对象,应该如何做呢?
Object.deepFreeze = (obj) => {
// 这里为什么不使用Object.keys(), 因为它无法获取不能枚举的属性, 我们要保证获取到所有的key
var propNames = Object.getOwnPropertyNames(obj);
propNames.forEach(function(name) {
var prop = obj[name];
if (typeof prop === 'object' && prop !== null) {
// 递归
Object.deepFreeze(prop);
}
});
return Object.freeze(obj);
}
var obj = {
name: {
nickname: '橙某人'
}
};
var o = Object.deepFreeze(obj);
obj.name.nickname = 'yd';
console.log(obj); // {name: {nickname: '橙某人'}}
obj.name.nickname = 'YD';
console.log(obj); // {name: {nickname: '橙某人'}}
delete obj.name.nickname;
console.log(obj); // {name: {nickname: '橙某人'}}
结论:深冻结可以使用递归处理来自行解决。
密封对象 - Object.seal()
Object.seal() 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。(以上来自MDN的解释)
其实都和 Object.freeze() 方法差不多,但是,它能允许被更改!!!
增删查改
我们依旧用上面的例子,注意看注解的地方。
// 增删查改
var obj = {
name: '橙某人'
};
Object.seal(obj);
/**********本身属性**********/
// 增
obj.age = 18;
console.log(obj); // {name: "橙某人"}
// 删
delete obj.name;
console.log(obj); // {name: "橙某人"}
// 查
console.log(obj.name); // 橙某人
// 改
obj.name = 'yd';
console.log(obj); // {name: "yd"} !!! 可以被更改 !!!
/**********原型属性**********/
// 增 (删查改也可以, 就不写了)
obj.__proto__.age = 18;
console.log(obj); // {name: "yd", [[Prototype]]: {age: 18}};
// 覆盖整个原型对象
obj.__proto__ = {}; // 报错: Uncaught TypeError: #<Object> is not extensible
结论:被冻结的对象,无法对本身属性进行增删,只能查改;而对象的原型对象如常,只是不能直接进行覆盖整个原型对象的操作。
返回值
与上面 Object.freeze() 对应结论是完全一致的,就不在细说了。
浅密封
与上面 Object.freeze() 对应结论是完全一致的,就不在细说了。
深密封
Object.deepSeal = (obj) => {
var propNames = Object.getOwnPropertyNames(obj);
propNames.forEach(function(name) {
var prop = obj[name];
if (typeof prop === 'object' && prop !== null) {
Object.deepSeal(prop);
}
});
return Object.seal(obj);
}
至此,本篇文章就写完啦,撒花撒花。
希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。