游乐游手机版
首页/前端开发/文章详情

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

时间:2026-07-15 18:52
使用Object freeze()可冻结对象顶层属性,但无法递归处理嵌套对象。深层冻结需手动递归遍历子对象。Object defineProperty配合Object keys()或getOwnPropertyNames()实现更细粒度的只读设置。注意不可枚举属性、Proxy及Map等内置集合的内部状态无法被冻结。

先说结论:如果需要将对象的所有自有属性快速设置为只读,直接使用 Object.freeze() 是最简便的方法。但需要注意,这个方法只作用于当前层级,不会递归处理嵌套对象——换言之,只能冻结浅层结构。

Ja vaScript 中如何批量将对象所有属性设置为只读

下面我们详细拆解几种实现方式,并梳理一些容易忽略的坑点。

基础用法:冻结顶层对象

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 }

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

当遇到嵌套对象时,例如对象内部包含子对象或数组,就需要手动递归冻结。大致思路是:先判断当前值是否为普通对象或数组(需排除 null、基本类型、DateRegExp 等),然后对每个可遍历的自有属性递归调用冻结函数,最后再冻结当前层。

一个简洁的实现如下:

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,但保留 configurabletrue——那么 Object.freeze() 就略显僵硬。此时可以借助 Object.defineProperty 配合 Object.keys() 逐属性设置。

注意:Object.keys() 仅处理可枚举属性;若要覆盖不可枚举属性,则需使用 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 能覆盖到,因此不算大坑);
  • 无法冻结 ProxyMapSet 等内置集合的内部状态——你只能冻结它们对外暴露的引用,内部数据结构仍然可能被修改;
  • 冻结之后,属性值依然可以读取,方法也能正常调用。但如果方法内部修改了 this 或外部变量,冻结就无能为力了;
  • 在 ES6 模块中,默认导出对象常配合 Object.freeze() 使用,目的就是确保 API 稳定,防止意外篡改。

这些细节并不复杂,但很容易被忽视。稍微留意一下,就能避免许多隐蔽的错误。

来源:https://www.php.cn/faq/2786465.html
上一篇JavaScript Number数值溢出时的表现行为 下一篇JavaScript中使用hasOwnProperty实现简单的对象深度对比实例教程
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
JavaScript动态加载与执行脚本的完整使用方法详解
前端开发 · 2026-07-17

JavaScript动态加载与执行脚本的完整使用方法详解

动态加载JavaScript脚本主要有三种方式:通过document createElement插入标签兼容性最好;import()支持按需加载ES模块并返回Promise;eval或Function构造器适用于执行代码字符串但风险较高。使用时需注意避免重复加载、处理超时及服务端渲染环境。

箭头函数多行逻辑的书写优化
前端开发 · 2026-07-17

箭头函数多行逻辑的书写优化

箭头函数多行逻辑需用花括号包裹并显式return,否则返回undefined;单行仅限一个表达式自动返回;返回对象字面量必须加小括号;复杂逻辑应拆分为独立函数,避免硬塞导致代码混乱。

如何设计JavaScript函数缓存防止内存无限增长
前端开发 · 2026-07-17

如何设计JavaScript函数缓存防止内存无限增长

防止函数缓存导致内存无限增长,需主动控制容量和寿命。采用LRU策略自动淘汰闲置条目,设定TTL防止脏数据长期驻留,优化键生成避免冗余堆积,并提供手动清理接口配合业务生命周期。

JavaScript布尔值转换核心逻辑详解
前端开发 · 2026-07-17

JavaScript布尔值转换核心逻辑详解

JavaScript布尔转换遵循明确的真值与假值规则,仅有6个假值:false、0、空字符串、null、undefined、NaN,其余所有值包括空数组、空对象均为真值。显式转换推荐Boolean(),隐式转换常见于条件判断与逻辑运算,需注意??与||的区别。

如何利用Performance API识别长任务来源的完整方法详解
前端开发 · 2026-07-17

如何利用Performance API识别长任务来源的完整方法详解

利用性能API识别长任务来源,需结合时间锚点、开发者工具验证和主动埋点。通过性能观察者捕获基础信息,使用性能标记缩小范围,借助Chrome开发者工具定位代码行,最后通过主动埋点验证,将长任务映射到具体代码段。