原生Object身上带的freeze方法是浅冻结,这里我们写 一个深度冻结。也就是浅冻+递归浅冻。
作用:冻结一个对象,让其不能再 增/减/改 属性。
也不能修改该对象已有属性的 可枚举性、可配置、可写性、也不能修改已有属性的值和它的原型属性,返回被冻住的传递的对象,而不是创建一个被冻结的副本。
知识储备
- 对象的三大特性:扩展性、密封性、冻结性。
- 扩展性:是否可添加新属性。Object.preventExtensions
- 密封性:不可增减属性,但已有属性可改。Object.seal
- 冻结性:seal基础上不可改值。分浅冻、 深冻。浅冻结:就是只冻结一层。Object.freeze
三个属性对应的判断方法:Object.isExtensible、Object.isSealed、Object.isFrozen
实现步骤
- 先对 对象 进行密封,这样对象就不可以增减属性
- 然后改写的属性配置,把是否可写 关闭
- 如果子还是对象进一步递归调用自身进行冻结。
代码实现
function _freeze(obj){
if(obj instanceof Object){
Object.seal(obj) //1.密封
for(let key in obj){
if(obj.hasOwnProperty(key)){
Object.defineProperty(obj,key,{
writable:false //2.不可改
})
}
_freeze(obj[key]) //3.递归 深度冻结
}
}
}
换一种写法:
代码实现
function deepFreeze(obj) {
// 取回定义在obj上的属性名
var propNames = Object.getOwnPropertyNames(obj);
// 在冻结自身之前冻结属性
propNames.forEach(function(name) {
var prop = obj[name];
// 如果子是个对象,冻结它
if (typeof prop == 'object' && prop !== null)
deepFreeze(prop);
});
// 冻结自身(no-op if already frozen)
return Object.freeze(obj);
}
代码测试
let obj = {
people:{
name:"macrolam"
}
}
_freeze(obj)
obj.people.age = 30
console.log(obj)//age并没有添加成功
console.log(Object.isFrozen(obj) === true);//true 读取是否被冻结