proxy核心是创建拦截层,不修改原对象而返回新代理对象,通过handler定义get、set等trap控制操作;需用reflect避免死循环,适用于只读封装等场景。

JavaScript 中用 Proxy 代理对象,核心是创建一个“拦截层”,让对目标对象的读写、调用等操作先经过自定义逻辑处理。它不修改原对象,而是返回一个新代理对象,所有访问都走你写的拦截器(handler)。
如何创建基础 Proxy 代理
Proxy 构造函数接收两个参数:目标对象和处理器对象(handler)。handler 里定义各种陷阱(trap),比如 get、set、has 等。
- 目标对象可以是普通对象、数组、甚至 null(但需注意某些 trap 不适用)
- handler 是一个普通对象,键名对应拦截方法,值是函数
- 没定义的 trap 会默认转发操作到原对象,不会报错
示例:
const target = { name: 'Alice', age: 30 };
const handler = {
get(obj, prop) {
console.log(`读取属性: ${prop}`);
return obj[prop];
},
set(obj, prop, value) {
console.log(`设置 ${prop} = ${value}`);
obj[prop] = value;
return true; // 必须返回 true 表示赋值成功
}
};
const proxy = new Proxy(target, handler);
proxy.name; // 输出:读取属性: name → "Alice"
proxy.age = 31; // 输出:设置 age = 31
常用 trap 及典型用途
不同 trap 对应不同操作场景,选对方法才能精准控制行为。
- get:拦截属性读取,适合做响应式、日志、默认值 fallback
- set:拦截属性赋值,可用于数据校验、只读限制、自动触发更新
-
has:拦截
in操作符,可隐藏属性或模拟稀疏数组 -
ownKeys:拦截
Object.keys()、for...in等,控制枚举行为 - apply 和 construct:分别拦截函数调用和 new 调用,用于装饰函数或类
注意:set 必须显式返回 true 才算赋值成功;get 返回 undefined 不代表失败,只是值为 undefined。
避免常见陷阱
Proxy 使用不当容易引发无限循环或静默失败。
- 在
get或set中直接读写obj[prop](即目标对象),可能触发自身 trap,造成死循环 —— 应改用Reflect.get(obj, prop)或Reflect.set(obj, prop, value) - 代理数组时,
push、pop等方法内部会触发多个 trap(如get、set、length更新),需配合Reflect正确转发 - Proxy 无法代理私有字段(#field),也不能代理不可扩展对象的新增属性(除非 handler 显式允许)
- 代理后的对象与原对象不相等(
proxy !== target),且instanceof判断可能失效
实际小例子:只读对象封装
用 Proxy 快速实现一个浅层只读包装:
function readonly(obj) {
return new Proxy(obj, {
set() {
throw new Error('Cannot modify a readonly object');
},
deleteProperty() {
throw new Error('Cannot delete property from readonly object');
},
defineProperty() {
throw new Error('Cannot define property on readonly object');
}
});
}
const data = { x: 1 };
const ro = readonly(data);
ro.x = 2; // 抛出错误
这种封装比冻结(Object.freeze)更灵活 —— 冻结后连原型链都无法修改,而 Proxy 可按需定制拦截粒度。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











