Proxy 和 Reflect 是 JavaScript 实现元编程的核心工具:Proxy 用于拦截并自定义对象操作,Reflect 提供统一的底层操作接口,二者配合可安全可靠地扩展对象行为。

Proxy:为对象装上“拦截器”
Proxy 用于创建一个代理对象,它能拦截对目标对象的各类底层操作(称为“trap”),并在执行前后插入自定义逻辑。
基本语法:
const proxy = new Proxy(target, handler);
- target:要代理的原始对象
-
handler:一个配置对象,定义各种 trap 方法,如
get、set、has、apply等
常见用途:
- 数据响应式(如 Vue 3 的 reactive):在
set时触发更新通知 - 访问控制:阻止读取敏感字段,或对未定义属性抛出友好错误
- 日志/调试:记录每次属性访问或修改
- 验证与转换:在赋值前校验类型、格式,或自动转换值
Reflect:统一的对象底层操作接口
Reflect 是一个内置对象,提供了一组静态方法,对应所有可被 Proxy 拦截的操作(如 Reflect.get()、Reflect.set())。它不是用来替代原生操作符(如 obj.prop),而是为了:
立即学习“Java免费学习笔记(深入)”;
- 提供可编程调用方式(比如方法名可动态传入)
- 与 Proxy 配合使用时保持语义一致和可预测性
- 替代部分已被废弃的 Object API(如
Object.defineProperty的替代方案更统一)
例如:
const obj = { a: 1 };
Reflect.get(obj, 'a'); // 1
Reflect.set(obj, 'b', 2); // true(成功返回 true)
Reflect.has(obj, 'a'); // true
Proxy + Reflect:协作实现可靠元编程
单独用 Proxy 定义 trap 时,若需转发操作到原对象,直接写 target[prop] 或 target[prop] = value 可能绕过原型链、不兼容 setter、或无法正确处理 this。而 Reflect 方法天然支持这些细节,推荐配合使用。
典型写法示例(带默认行为的代理):
const target = { x: 1 };
const proxy = new Proxy(target, {
get(target, prop, receiver) {
console.log(`读取 ${prop}`);
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
console.log(`设置 ${prop} = ${value}`);
return Reflect.set(target, prop, value, receiver);
}
});
-
receiver参数确保super、this和 getter/setter 中的绑定正确(尤其涉及继承时) - 所有 Reflect 方法都返回明确的成功状态(布尔值),便于做条件控制
- 避免手动实现容易出错的底层逻辑(如属性查找规则、原型链遍历)
实际能做什么:几个轻量但有力的例子
1. 防止意外属性写入(开发环境只读保护)
function frozenObj(obj) {
return new Proxy(obj, {
set() {
throw new Error('禁止修改对象属性(开发模式)');
}
});
}
2. 自动初始化嵌套属性(类似 Lodash 的 set)
function autoCreate(target) {
return new Proxy(target, {
get(target, prop) {
if (!(prop in target)) target[prop] = {};
return Reflect.get(target, prop);
}
});
}
const obj = autoCreate({});
obj.a.b.c = 123; // 不报错,自动创建 a 和 b
3. 函数调用日志与耗时统计
function logCalls(fn) {
return new Proxy(fn, {
apply(target, thisArg, args) {
console.time(`call ${fn.name}`);
const result = Reflect.apply(target, thisArg, args);
console.timeEnd(`call ${fn.name}`);
return result;
}
});
}
Proxy 和 Reflect 共同构成了 JavaScript 中最自然、最安全的元编程能力。它们不改变语言语法,却大幅拓展了对象行为的表达边界——关键不在于“能做什么”,而在于“如何让行为更可预测、更易维护、更贴近业务意图”。











