『你不知道的Object』之『freeze对象冻结』【JavaScript面试不艰难系列】
Object.freeze
方法可以冻结一个对象,一个冻结后的对象再也不能被修改。首先介绍一下基本用法:
语法
Object.freeze(obj)
参数
obj:要被冻结的对象
返回值
被冻结的对象
let obj={
a:1,
b:2
}
let newObj=Object.freeze(obj);
console.log(newObj===obj) // true
也就是说返回的对象跟源对象是同一个引用,并且对象被冻结后是只读的:
let obj={
a:1,
b:2
}
Object.freeze(obj);
console.log(obj.a) // 1
我们可以用Object.isFrozen
方法来检测一个对象是否是被冻结过的对象
let obj={
a:1,
b:2
}
Object.freeze(obj);
console.log(Object.isFrozen(obj)) // true
被冻结对象自身的所有属性都不能以任何方式被修改。任何修改尝试都会失败,包括添加、修改、删除:
let obj={
a:1,
b:2
}
Object.freeze(obj);
obj.c=3;
console.log(obj) // {a:1,b:2} 冻结了一个对象则不能向这个对象添加新的属性
obj.a=11;
console.log(obj) // {a:1,b:2} 冻结了一个对象则不能修改这个对象中的属性
delete obj.a
console.log(obj) // {a:1,b:2} 冻结了一个对象则不能删除已有属性
以上在非严格模式下都不会有报错,但当我们处于严格模式下时:
"use strict";
let obj = {
a: 1,
b: 2,
};
Object.freeze(obj);
obj.a = 11;
console.log(obj); // TypeError: Cannot assign to read only property 'a' of object 提示该属性是只读的
obj.c=3;
console.log(obj) // TypeError: Cannot add property c, object is not extensible 提示该对象是不可扩展的
修改原型
注意对象一旦被冻结之后该对象的原型也不可以被修改:
function Test() {
this.a = 1;
this.b = 2;
}
Test.prototype.c=3
let obj = new Test();
Object.freeze(obj);
obj.__proto__={aaa:111}
console.log(obj) // Error: #<Test> is not extensible 是不可扩展的
但是原型中的属性却可以被修改,这是因为Object.freeze
方法是浅冻结,也就是说只会冻结一层:
function Test() {
this.a = 1;
this.b = 2;
}
Test.prototype.c=3
let obj = new Test();
Object.freeze(obj);
obj.__proto__.c=4
console.log(obj.c) // 4
// 原型也是一个对象,根据以下结构可以看出,原型里又是一个对象,所以原型对象里的属性是冻结不了的
// obj:{
// a:1,
// b:2,
// 原型:{
// c:3
// }
// }
不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。
let obj={
a:1,
b:2
}
Object.defineProperty(obj,"a",{
value:1,
//enumerable:false
//configurable:false,
//writable:false
})
console.log(obj) // Cannot redefine property: a at Function.defineProperty
通过对象的get
和set
方法也不能修改冻结后的对象
let obj = {
a: 1,
b: 2,
get() {
return this.a;
},
set(newVal) {
this.a = newVal;
},
};
Object.freeze(obj);
obj.a = 11;
console.log(obj); // {a:1,b:2}
在 ES5 中,如果这个方法的参数不是一个对象(一个原始值),那么它会导致 TypeError
。在 ES6 中,非对象参数将被视为要被冻结的普通对象,并被简单地返回。
// ES6
let res=Object.freeze(123); // true
console.log(res); // 123 // true
// ES5
let res=Object.freeze(123);
console.log(res) // TypeError: 123 is not an object
也可以传入数组参数
let arr=[1,2,3];
Object.freeze(arr);
arr.push(4)
console.log(arr) // Cannot add property 3, object is not extensible
// 上述报错是因为数组也是一个特殊的对象,可以转换为以下结构,故也不能被新增、修改、删除
// arr={
// "0":1,
// "1":2,
// "2":3,
// "3":4
//}
下面来实现一个深冻结:
let obj = {
a: 1,
b: 2,
c: {
d: 3,
e: 4,
f: {
g: 5,
},
},
};
// 在Object对象上添加一个新的方法
Object.deepFreeze=function(obj){
let keys=Object.getOwnPropertyNames(obj) // 获取对象自身所有属性(包括不可枚举属性)
// 递归执行
if(keys.length>0){
keys.forEach(name=>{
if(typeof obj[name] == "object" && obj[name] != null){
Object.deepFreeze(obj[name])
}
})
}
return Object.freeze(obj)
}
Object.deepFreeze(obj);
// ...同以上新增、修改、删除相同
obj.c.f.g = 333;
console.log(obj); // {a:1,b:2,c{d:3,e:4,f{g:5}}} 所有属性都不可被修改
这样一个深度冻结就实现啦! 下次见~
转载自:https://juejin.cn/post/7214373797691473975