proxy 本身不能直接加锁,但可通过拦截操作配合内部状态标记模拟防篡改行为;它支持 set、deleteproperty、defineproperty、setprototypeof、preventextensions 等全面拦截,比 object.freeze 更灵活,但仅对 proxy 访问生效且有性能开销。

Proxy 本身不能直接“加锁”,但它能拦截对象操作,配合内部状态标记,可模拟防篡改(即冻结式保护)行为。核心思路是:用 Proxy 拦截所有可能修改的操作(如设置属性、删除、添加),并在拦截器中根据是否“已锁定”来决定是否放行。
用 Proxy 模拟 Object.freeze 的增强版锁定
Object.freeze 只能冻结已有属性,且无法阻止原型链或 Symbol 属性的修改。Proxy 可覆盖更广的操作,包括 set、deleteProperty、defineProperty、setPrototypeOf、preventExtensions 等。
- 创建一个私有标志(如闭包变量或 WeakMap 存储锁定状态)
- 在每个相关 trap 中检查该标志,若已锁定则拒绝修改并抛出错误或静默忽略
- 提供显式
lock()和unlock()方法(可选)
基础锁定实现(不可逆锁定)
以下是一个轻量、不可逆的锁定封装:
function createLockedObject(target) {
const isLocked = new WeakMap();
isLocked.set(target, false);
const handler = {
set(obj, prop, value, receiver) {
if (isLocked.get(target)) {
throw new TypeError(`Cannot assign to read-only property '${prop}'`);
}
return Reflect.set(obj, prop, value, receiver);
},
deleteProperty(obj, prop) {
if (isLocked.get(target)) {
throw new TypeError(`Cannot delete property '${prop}'`);
}
return Reflect.deleteProperty(obj, prop);
},
defineProperty(obj, prop, descriptor) {
if (isLocked.get(target)) {
throw new TypeError(`Cannot define property '${prop}'`);
}
return Reflect.defineProperty(obj, prop, descriptor);
},
setPrototypeOf(obj, proto) {
if (isLocked.get(target)) {
throw new TypeError('Cannot set prototype of locked object');
}
return Reflect.setPrototypeOf(obj, proto);
},
preventExtensions() {
if (isLocked.get(target)) {
throw new TypeError('Cannot prevent extensions on locked object');
}
return Reflect.preventExtensions(target);
}
};
const proxy = new Proxy(target, handler);
// 提供 lock 方法
proxy.lock = function() {
isLocked.set(target, true);
};
return proxy;
}
// 使用示例
const obj = { a: 1 };
const locked = createLockedObject(obj);
console.log(locked.a); // 1
locked.lock();
locked.a = 2; // TypeError
支持解锁与状态查询的增强版本
若需支持临时解锁(谨慎使用),可将锁定状态改为可变,并增加 isLocked() 查询方法:
- 用 WeakMap 存储每个目标对象的锁定状态,避免内存泄漏
- 暴露
lock()、unlock()和isLocked()方法到 proxy 上 - 所有 trap 统一检查
isLocked(target),保持逻辑一致 - 注意:解锁不恢复被 Proxy 拦截过的中间状态(如已删属性不会自动回来)
注意事项与局限
Proxy 锁定不是底层语言级防护,它依赖运行时拦截,存在几个关键点:
- 仅对通过 proxy 访问的操作生效;原始 target 若被直接引用,仍可被修改(应避免暴露 target)
- 无法拦截 `Object.assign` 对 proxy 的浅拷贝(因为 assign 内部用的是 [[Get]]/[[Set]],会被 trap 拦截,但若目标是普通对象则绕过 proxy)
- 性能开销比原生 freeze 略高,高频读写场景需权衡
- 不能防止原型污染(除非显式拦截
__proto__或setPrototypeOf,上面示例已包含)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











