reflect.preventextensions 不能直接锁定代理对象,只能作用于目标对象;需先锁定目标对象,再在 proxy handler 中正确拦截 preventextensions 和 isextensible 操作以确保语义一致。

Reflect.preventExtensions 本身不能直接“锁定代理对象”,它只能作用于目标对象(target),而代理(Proxy)的行为由其 handler 定义。要让代理对象表现得像被 Object.preventExtensions 锁定一样,关键在于:在 Proxy 的 handler 中拦截并控制 preventExtensions 和 isExtensible 操作,并确保目标对象本身已被锁定。
1. 先锁定目标对象,再创建代理
这是最基础也最可靠的做法。只有目标对象本身不可扩展,代理才可能真正阻止新增属性:
- 调用
Reflect.preventExtensions(target)或Object.preventExtensions(target)锁定原始对象 - 创建 Proxy 时,handler 中的
preventExtensions返回true(表示操作成功),isExtensible返回false - 这样即使外部调用
Reflect.preventExtensions(proxy),也会按 handler 规则响应,且无法绕过锁定
2. 在 handler 中正确拦截 preventExtensions 和 isExtensible
如果不拦截,Proxy 默认会转发这些操作到目标对象。但若目标已锁定,转发后也能生效;不过显式拦截更可控、语义更清晰:
-
preventExtensions() { return Reflect.preventExtensions(target); }—— 确保调用有效 -
isExtensible() { return Reflect.isExtensible(target); }—— 返回真实状态,避免误判 - 一旦目标被锁定,
Reflect.isExtensible(proxy)就会返回false,后续添加属性(如proxy.newProp = 1)在严格模式下会抛错
3. 注意:Proxy 本身不会自动继承目标的不可扩展性
即使目标已被 preventExtensions,若 handler 没有正确实现 isExtensible,Proxy 可能仍报告为可扩展:
- 错误写法:
isExtensible: () => true→ 代理看似可扩展,但赋值会失败,行为不一致 - 正确写法:
isExtensible: () => Reflect.isExtensible(target)→ 与目标保持同步 - 同理,
preventExtensions拦截应返回操作结果(通常为true),否则调用会失败
4. 实际使用示例
下面是一个完整可运行的例子:
const target = {};
Reflect.preventExtensions(target); // 先锁定目标
const proxy = new Proxy(target, {
preventExtensions() {
return Reflect.preventExtensions(target); // 转发并确保成功
},
isExtensible() {
return Reflect.isExtensible(target); // 如实反映目标状态
}
});
console.log(Reflect.isExtensible(proxy)); // false
proxy.foo = 'bar'; // 严格模式下:TypeError;非严格模式下静默失败
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











