1. 测试对象
let like = Symbol("like");
let obj = {
name: "Lawson",
age: 18,
innerObj: {
innerName: "innerName",
innerAge: 30,
},
[like]: {
symbolName: "SymbolName",
},
};
Object.defineProperty(obj, "myProp", {
writable: false,
enumerable: false,
configurable: true,//如果为false,则描述属性不能被配置
value: "myPropVal",
});
let objRet = Object.freeze(obj);
2. 被冻结对象特点
- 【不能】添加新的属性
obj.sex = '男'
console.log(obj.sex);//undefined
- 【不能】删除已有属性
delete obj.age;
console.log(obj.age);//18
- 【不能】修改已有属性的值
obj.age = 20
console.log(obj.age);//18
- 【不能】修改该对象已有属性的可枚举性
enumerable
、可配置性configurable
、可写性writable
console.log(Object.getOwnPropertyDescriptor(obj, 'myProp'));
/* {
value: 'myPropVal',
writable: false,
enumerable: false,
configurable: false //已经不能被配置了
} */
- 【不能】修改原型
obj.__proto__ = Object.create(null); //Uncaught TypeError: #<Object> is not extensible
console.log(obj.__proto__);
- 返回和传入的参数相同的对象(同一堆地址)
//隐式转换,相同类型Object只比较堆地址
console.log(objRet == obj);//true
3. 深冻结
obj.innerObj.innerAge = 29;
console.log(obj.innerObj.innerAge);//29 被成功修改,浅冻结失效
3.1 通用代码
function deepFreeze(obj) {
// 取回定义在obj上的属性名
var propNames = Reflect.ownKeys(obj);
// 在冻结自身之前冻结属性
propNames.forEach(function (name) {
var prop = obj[name];
// 如果prop是个对象,冻结它
if (typeof prop == "object" && prop !== null) {
deepFreeze(prop);
}
});
// 冻结自身(no-op if already frozen)
return Object.freeze(obj);
}
测试
deepFreeze(obj);
obj.innerObj.innerAge = 29;
console.log(obj.innerObj.innerAge); //30
obj[like].symbolName = "Shery";
console.log(obj[like].symbolName); //SymbolName
4. 使用场景
- 复杂枚举类
参考文章:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze