Proxy 用于全面拦截对象操作,Reflect 提供标准操作方法;Proxy 可捕获新增/删除属性、in 操作等 13 种行为,Object.defineProperty 则不能;Reflect 应在 Proxy trap 中调用以确保原型链、私有字段和 receiver 正确性。
代理(Proxy)和反射(Reflect)是 JavaScript 中一对协作的底层机制:前者用于拦截并自定义对象操作,后者提供一套与 Proxy 拦截器一一对应的、更规范的对象操作方法。它们不是语法糖,而是运行时可控性的基础设施。
Proxy 而不是 Object.defineProperty
Object.defineProperty 只能监听已存在的属性读写,无法捕获新增属性、删除属性、in 操作、for...in 遍历等行为;而 Proxy 可以拦截 13 种操作,覆盖更全。
obj.newProp = 1)→ 必须用 Proxy
delete obj.x 或 obj instanceof SomeClass → Proxy 提供 deleteProperty 和 getPrototypeOf 等 traparr[0] = 'x')→ Object.defineProperty 对数组索引无效,Proxy 的 set 可捕获Proxy 不能代理非对象(如原始值),也不能直接代理 undefined 或 null
Reflect 不是可选的“工具库”,它是 Proxy 拦截器的默认行为实现每个 Proxy 的 trap(如 get、set)里,推荐用 Reflect.get()、Reflect.set() 等调用原生逻辑,而不是手写 target[prop] —— 因为后者不支持原型链查找、不触发其他 trap、也不兼容私有字段(#field)。
const handler = {
get(target, prop, receiver) {
console.log(`读取 ${prop}`);
// ✅ 正确:走标准语义,支持原型、私有字段、receiver 绑定
return Reflect.get(target, prop, receiver);
// ❌ 错误:绕过原型,忽略 receiver,对 #field 报错
/
/ return target[prop];
}
};
Reflect 方法全部返回布尔值或结果值,不会抛异常(如 Reflect.deleteProperty() 返回 true/false,而非抛错)Reflect.construct() 是唯一能指定 new.target 的方式,用于子类化内置构造器(如继承 Array)Reflect 方法的第一个参数都是目标对象,第二个是属性名,参数顺序统一,比对应全局函数(如 Object.getOwnPropertyDescriptor)更一致这些不是“玩具示例”,而是真实工程中高频落地的模式。
set trap 中检查类型/范围,throw 或自动转换console.trace() 或性能标记)reactive() 就基于 Proxy + WeakMap 缓存依赖eval、Function 构造、document.write 等危险操作set trap 直接 throw,deleteProperty 返回 false,让对象“看起来”只读注意:Proxy 创建的是新对象,原对象不受影响;且一旦代理,就无法撤销(ECMAScript 没有 Proxy.revoke 的通用实现,仅 revocable 特殊形式支持一次撤销)。