JavaScript批量将对象所有属性设为只读
使用Object freeze()可冻结对象顶层属性,但无法递归处理嵌套对象。深层冻结需手动递归遍历子对象。Object defineProperty配合Object keys()或getOwnPropertyNames()实现更细粒度的只读设置。注意不可枚举属性、Proxy及Map等内置集合的内部状态无法被冻结。
先说结论:如果需要将对象的所有自有属性快速设置为只读,直接使用 Object.freeze() 是最简便的方法。但需要注意,这个方法只作用于当前层级,不会递归处理嵌套对象——换言之,只能冻结浅层结构。

下面我们详细拆解几种实现方式,并梳理一些容易忽略的坑点。
基础用法:冻结顶层对象
Object.freeze() 是最直接的方案,适用于简单的扁平对象。调用后,对象属性的 writable、configurable、enumerable 描述符都会被锁定。尝试修改属性值、新增属性或删除已有属性?在非严格模式下会静默失败,严格模式下直接抛出错误——行为非常明确。
但要记住:它只处理对象自身的属性,不会影响原型链中的属性。来看一个示例:
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、基本类型、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.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能覆盖到,因此不算大坑); - 无法冻结
Proxy、Map、Set等内置集合的内部状态——你只能冻结它们对外暴露的引用,内部数据结构仍然可能被修改; - 冻结之后,属性值依然可以读取,方法也能正常调用。但如果方法内部修改了
this或外部变量,冻结就无能为力了; - 在 ES6 模块中,默认导出对象常配合
Object.freeze()使用,目的就是确保 API 稳定,防止意外篡改。
这些细节并不复杂,但很容易被忽视。稍微留意一下,就能避免许多隐蔽的错误。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
JavaScript有效防止原型污染影响属性存在性检查
防止原型污染,进行属性存在性检查应使用`Object hasOwn()`绕过原型链上的属性,兼容旧环境时则使用`Object prototype hasOwnProperty call()`。避免使用`in`操作符或直接值判断。治本之策是移除`__proto__`等危险键,用`Object create(null)`创建无原型链的对象,并冻结`Object
如何利用Promise简化前端状态管理的高效实用方法
Promise的三种状态与链式调用天然适合组织异步流程,结合Promise withResolvers可解耦创建与决议。在UI框架中,Promise实例可直接驱动声明式状态渲染,减少手动维护变量,让状态管理回归本质,并提升代码可读性与可维护性,实现直观的异步状态驱动。
JavaScript内存泄露常见代码模式识别方法
JavaScript内存泄漏源于对象不可达却被强引用,典型模式包括意外全局变量、未清理的定时器、DOM引用残留、闭包长期持有大对象及模块静态引用累积。需借助DevTools堆快照定位持续增长的对象与保留者。
JavaScript展开运算符与深拷贝的不可变数据实现对比
展开运算符仅浅拷贝第一层属性,对嵌套对象无效但执行高效;深拷贝递归复制所有层级实现完全隔离,但存在性能开销与循环引用问题。实际开发中推荐组合展开运算符与手动深层覆盖,或借助Immer库,仅在嵌套极深时使用structuredClone。
V8引擎编译优化对JavaScript内存占用的影响
V8引擎的编译优化通过字节码紧凑表示节省约一半内存,隐藏类共享减少对象结构开销,TurboFan编译器执行常量折叠、死代码消除、内联及类型反馈精简表示,分代垃圾回收采用新生代半空间复制与老生代增量标记,有效控制内存峰值并加速短期对象回收。
- 热门数据榜
相关攻略
2026-07-18 06:46
2026-07-18 06:46
2026-07-18 06:46
2026-07-18 06:45
2026-07-18 06:45
2026-07-18 06:45
2026-07-18 06:45
2026-07-18 06:44
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

