【JS】深冻结

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

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容