什么是Proxy?常见使用场景有哪些?
1. 什么是 Proxy
Proxy 用于定义基本操作的自定义行为。
本质:修改程序的默认行为,就如同在编程语言层面上做修改,属于元编程(meta programming)。
元编程(Metaprogramming,又译超编程)是指某类计算机程序的编写,这类程序编写或者操纵其它程序(或者自身)作为它们的数据,或者在运行时完成部分本应在编译时完成的工作。
Proxy 亦是如此,用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
2. 用法
如果目标对象自身的某个属性不可写且不可配置,那么 set 方法将不起作用:
const obj = {};
Object.defineProperty(obj, 'foo', { value: 'bar', writable: false });
const handler = {
set(obj, prop, value) { obj[prop] = 'baz'; }
};
const proxy = new Proxy(obj, handler);
proxy.foo = 'baz';
proxy.foo; // "bar"
如果属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则会报错:
const target = Object.defineProperties({}, {
foo: { value: 123, writable: false, configurable: false }
});
const handler = {
get(target, propKey) { return 'abc'; }
};
const proxy = new Proxy(target, handler);
proxy.foo;
// TypeError: Invariant check failed
取消代理
const { proxy, revoke } = Proxy.revocable(target, handler);
revoke(); // 之后访问 proxy 会抛 TypeError
3. 使用场景
场景一:访问/修改受保护字段
let api = {
_apiKey: '123abc456def',
getUsers() {},
getUser(userId) {},
setUser(userId, config) {}
};
const RESTRICTED = ['_apiKey'];
api = new Proxy(api, {
get(target, key, proxy) {
if (RESTRICTED.indexOf(key) > -1) throw Error(`${key} 不可访问.`);
return Reflect.get(target, key, proxy);
},
set(target, key, value, proxy) {
if (RESTRICTED.indexOf(key) > -1) throw Error(`${key} 不可修改`);
return Reflect.set(target, key, value, proxy);
}
});
console.log(api._apiKey); // 报错
api._apiKey = '987654321'; // 报错
场景二:观察者模式
观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。
observable 函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数:
const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}
});
const obj = observable({ count: 0 });
observe(() => console.log('changed:', obj.count));
obj.count = 1; // 自动触发观察者
补充:Proxy 的常见用途:
- 数据校验(如 Vue 3 的响应式系统就是基于 Proxy)。
- 访问控制(私有字段保护)。
- 日志/埋点(自动记录属性读写)。
- 缓存 / lazy load(get 时才去取值)。
- 观察者/响应式:自动通知订阅者。
- 与
Reflect配合使用更规范:Reflect.get/Reflect.set等。
来源整理自:我的有道云笔记



