javascript 中 proxy 可通过拦截 set、deleteproperty 等陷阱方法并递归代理嵌套对象,实现真正彻底的只读保护,比 object.freeze 更可控、更深层;示例 readonly 函数支持缓存、错误提示与完整拦截。

JavaScript 中 Proxy 可以通过拦截对象的写入操作(如 set、deleteProperty)和防止对象被扩展(preventExtensions),来实现真正意义上的只读保护——不仅阻止属性赋值,还能禁用新增、删除、重配置等修改行为。
拦截关键陷阱方法,拒绝所有写操作
只读不是简单“不让改值”,而是要覆盖所有可能改变对象状态的代理捕获器:
-
set:返回
false或抛出错误,阻止任何属性赋值(包括新增属性) -
deleteProperty:始终返回
false,禁止delete obj.key -
defineProperty:返回
false,禁用Object.defineProperty -
preventExtensions:返回
true,确保对象不可扩展(这是Object.freeze的底层前提) -
setPrototypeOf:返回
false,防止修改原型链
递归冻结嵌套对象,避免浅层只读漏洞
Proxy 默认只代理第一层。若目标含嵌套对象,需在 get 拦截中对返回的 object 类型值自动包装为只读 Proxy:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 检查
value是否为普通对象且未被代理过 - 用同一套只读 handler 递归代理该值,并缓存避免重复创建
- 注意避免循环引用(可用
WeakMap缓存已代理对象)
与 Object.freeze 的区别:Proxy 更彻底、更可控
Object.freeze 是浅冻结,且无法拦截 in、for...in 等操作;Proxy 可:
- 在
has和ownKeys中控制属性可见性(例如隐藏某些字段) - 在
get中统一处理 getter 行为(如返回深拷贝防止外部篡改) - 配合
Reflect委托安全操作,同时保留原始语义(如get仍可读取原型链)
一个轻量实用的只读 Proxy 工具函数
以下是一个生产可用的只读封装(支持嵌套、缓存、错误提示):
function readonly(obj) {
const cache = new WeakMap();
const handler = {
get(target, key, receiver) {
const value = Reflect.get(target, key, receiver);
if (value !== null && typeof value === 'object' && !cache.has(value)) {
cache.set(value, readonly(value));
}
return cache.get(value) ?? value;
},
set() { throw new TypeError('Cannot modify read-only object'); },
deleteProperty() { throw new TypeError('Cannot delete property of read-only object'); },
defineProperty() { throw new TypeError('Cannot define property on read-only object'); },
preventExtensions() { return true; },
setPrototypeOf() { throw new TypeError('Cannot change prototype of read-only object'); }
};
return new Proxy(obj, handler);
}
调用 readonly({ a: 1, b: { c: 2 } }) 后,任意层级均不可写,且尝试修改会明确报错,便于调试定位。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










