JavaScript 中怎样批量将对象所有属性设为只读

作者:袖梨 2026-07-09
Object.freeze()可将对象自身属性设为只读,但不递归冻结嵌套对象;深层冻结需手动递归实现;替代方案可用Object.defineProperty批量设置属性描述符;存在无法冻结Proxy、Map等内置类型及不可枚举symbol属性等限制。

可以通过 Object.freeze() 快速将对象所有自有属性设为只读(不可修改、不可添加、不可删除),但需注意它只作用于对象**自身属性**,不递归冻结嵌套对象。

基础用法:冻结顶层对象

Object.freeze() 是最直接的方式,适用于简单扁平对象:

  • 调用后,属性的 writableconfigurableenumerable 描述符均被锁定
  • 尝试修改属性值、添加新属性或删除属性会静默失败(非严格模式)或抛出错误(严格模式)
  • 仅冻结对象自身的属性,原型链上的属性不受影响

示例:

const obj = { a: 1, b: 2 };Object.freeze(obj);obj.a = 99;      // 无效(静默)obj.c = 3;       // 无效(静默)delete obj.b;    // 无效(静默)console.log(obj); // { a: 1, b: 2 }

深层冻结:递归冻结嵌套对象

若对象含嵌套对象(如数组、子对象),需手动递归处理:

立即学习“Java免费学习笔记(深入)”;

  • 先检查值是否为普通对象或数组(排除 null、基本类型、Date、RegExp 等)
  • 对每个可遍历的自有属性值递归调用冻结函数
  • 最后再冻结当前对象自身

简易实现:

function deepFreeze(obj) {  if (obj && typeof obj === 'object' && !Object.isFrozen(obj)) {    Object.getOwnPropertyNames(obj).forEach(prop => {      if (obj[prop] !== null && typeof obj[prop] === 'object') {        deepFreeze(obj[prop]);      }    });    Object.freeze(obj);  }  return obj;}

使用:deepFreeze({ a: 1, nested: { x: 2 } })nested.x 也无法修改。

替代方案:使用 Object.defineProperty 批量设置

若需更精细控制(例如只设 writable: false,但保留 configurable: true),可用 Object.defineProperty 配合 Object.keys()

  • 遍历所有自有可枚举属性
  • 逐个将其描述符设为 { writable: false, configurable: false }(等效于 freeze 的效果)
  • 注意:此方式不自动处理不可枚举属性,需用 Object.getOwnPropertyNames() 覆盖

示例:

function makeAllReadOnly(obj) {  Object.getOwnPropertyNames(obj).forEach(key => {    Object.defineProperty(obj, key, {      writable: false,      configurable: false,      enumerable: true // 保持原有枚举性    });  });  return obj;}

注意事项与限制

Object.freeze() 和类似操作有明确边界:

  • 不能冻结 symbol 属性以外的不可枚举属性(但 getOwnPropertyNames 可覆盖)
  • 无法冻结 Proxy、Map、Set 等内置集合类的内部状态,只能冻结其引用
  • 冻结后仍可读取属性、调用方法;方法内部若修改 this 或外部变量,不受限制
  • ES6 模块默认导出对象常配合 freeze 使用,确保 API 稳定

不复杂但容易忽略。

相关文章

精彩推荐