javascript中可通过proxy实现只读代理,拦截set、defineproperty、deleteproperty、setprototypeof四个trap并抛出typeerror;基础版为浅只读,深层只读需在get中递归代理对象属性,配合object.freeze可增强安全性。

JavaScript 中可以通过 Proxy 拦截对对象的写入操作(如 set、defineProperty、deleteProperty),配合 get 拦截返回原始值,从而实现真正意义上的只读代理——外部无法修改属性,也无法添加或删除属性。
核心拦截器:禁用所有写操作
只读的关键在于拒绝所有可能改变目标对象状态的操作。主要需拦截以下 4 个 trap:
-
set:拦截赋值(
obj.x = 1),始终返回false或抛错 -
defineProperty:拦截
Object.defineProperty,防止新增/重配置属性 -
deleteProperty:拦截
delete obj.x,禁止删除 -
setPrototypeOf:拦截
Object.setPrototypeOf,防止篡改原型链
基础只读 Proxy 实现
以下是一个简洁可靠的只读代理构造函数:
function readOnly(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
return Reflect.get(target, key, receiver);
},
set() {
throw new TypeError('Cannot modify read-only object');
},
defineProperty() {
throw new TypeError('Cannot define property on read-only object');
},
deleteProperty() {
throw new TypeError('Cannot delete property from read-only object');
},
setPrototypeOf() {
throw new TypeError('Cannot set prototype on read-only object');
}
});
}
使用示例:
macOS 微信消息自动化工具。通过 GUI 自动化实现:发送消息给指定联系人、读取聊天内容、监控新消息。适用于需要自动化微信操作的场景,如定时发送、批量回复、消息备份等。依赖 peekaboo 进行屏幕截图和 UI 交互。仅支持 macOS。开源地址:https://github.com/chairmanmia...
const data = { a: 1, b: { c: 2 } };
const ro = readOnly(data);
<p>ro.a = 99; // ❌ 抛出 TypeError
ro.d = 3; // ❌ 抛出 TypeError
delete ro.a; // ❌ 抛出 TypeError
Object.defineProperty(ro, 'x', { value: 1 }); // ❌ 抛出 TypeError</p>
注意:只读是浅层的,嵌套对象仍可变
上述实现只保护第一层属性。若属性值本身是对象(如 b: { c: 2 }),其内部仍可被修改:
ro.b.c = 99; // ✅ 成功!b 是普通对象,未被代理
如需**深层只读**,需在 get 中对返回的对象值递归代理:
function deepReadOnly(obj) {
if (obj !== null && typeof obj === 'object' && !Array.isArray(obj)) {
return new Proxy(obj, {
get(target, key, receiver) {
const value = Reflect.get(target, key, receiver);
// 对普通对象(非 Date、RegExp 等内置类型)递归代理
if (value !== null && typeof value === 'object' &&
!value.constructor || value.constructor === Object) {
return deepReadOnly(value);
}
return value;
},
set() { throw new TypeError('Cannot modify read-only object'); },
defineProperty() { throw new TypeError('Cannot define property on read-only object'); },
deleteProperty() { throw new TypeError('Cannot delete property from read-only object'); },
setPrototypeOf() { throw new TypeError('Cannot set prototype on read-only object'); }
});
}
return obj;
}
补充:冻结原对象提升安全性
Proxy 只拦截外部访问,但若有人持有原始对象引用,仍可绕过代理直接修改。为彻底防护,建议在创建只读代理前先 Object.freeze 原对象(对顶层属性):
function readOnly(obj) {
Object.freeze(obj); // 冻结自身(浅冻结)
return new Proxy(obj, { /* traps as above */ });
}
注意:Object.freeze 也是浅冻结,深层对象仍需手动处理或依赖 deepReadOnly 的递归代理逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










