proxy
1.proxy 简介
Proxy 是 ECMAScript 6(ES6)引入的一种元编程(metaprogramming)特性,它允许你创建对象的代理,以拦截和自定义对象上的基本操作。通过 Proxy,你可以监视、修改或拦截对象的属性访问、属性赋值、属性删除,以及其他一些操作,如函数调用、遍历等。Proxy 的主要用途包括:
属性访问拦截: 你可以拦截属性的读取操作,允许你在属性被访问时执行自定义的操作。
属性赋值拦截: 你可以拦截属性的写入操作,允许你在属性被修改时执行自定义的操作。
属性删除拦截: 你可以拦截属性的删除操作,允许你在属性被删除时执行自定义的操作。
函数调用拦截: 你可以拦截对象上的函数调用,允许你在函数被调用时执行自定义的操作。
遍历拦截: 你可以拦截对象的遍历操作,允许你自定义对象的遍历行为。
下面是一个更详细的示例,演示了 Proxy 的不同拦截操作:
// 创建一个目标对象
const target = {
name: "John",
age: 30,
};
// 创建一个代理对象,拦截属性访问操作
const handler = {
get: function (target, property) {
console.log(`Getting ${property}`);
return target[property];
},
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 触发代理的 get 操作,输出 "Getting name" 和 "John"
// 创建一个代理对象,拦截属性赋值操作
const handler2 = {
set: function (target, property, value) {
console.log(`Setting ${property} to ${value}`);
target[property] = value;
},
};
const proxy2 = new Proxy(target, handler2);
proxy2.age = 35; // 触发代理的 set 操作,输出 "Setting age to 35"
console.log(target.age); // 输出 35,代理修改了目标对象的属性
// 创建一个代理对象,拦截属性删除操作
const handler3 = {
deleteProperty: function (target, property) {
console.log(`Deleting ${property}`);
delete target[property];
},
};
const proxy3 = new Proxy(target, handler3);
delete proxy3.age; // 触发代理的 delete 操作,输出 "Deleting age"
console.log(target.age); // 输出 undefined,代理删除了目标对象的属性
Proxy 提供了强大的能力,但也需要小心使用,因为滥用它可能导致代码复杂性和性能问题。通常情况下,Proxy 用于实现高级功能,如数据验证、缓存、响应式编程、事件代理等。要深入了解 Proxy 的各种拦截操作和用例,建议参考 ECMAScript 规范或相关文档。
2.proxy 的所有 handler
const target = {};
const obj = new Proxy(target, {
get(target, propKey, receiver) {
// 拦截对象属性的读取,如 proxy.foo 和 proxy['foo']
},
set(target, propKey, value, receiver) {
// 拦截对象属性的设置,如 proxy.foo = v 或 proxy['foo'] = v
// 返回一个布尔值
},
has(target, propKey) {
// 拦截propKey in proxy的操作,返回一个布尔值
},
deleteProperty(target, propKey) {
// 拦截delete proxy[propKey]的操作,返回一个布尔值
},
ownKeys(target) {
// 拦截Object.getOwnPropertyNames(proxy)、
// Object.getOwnPropertySymbols(proxy)、
// Object.keys(proxy)以及for...in循环
// 返回一个数组
// 该方法返回目标对象所有自身的属性的属性名
// 而Object.keys()的返回结果仅包括目标对象自身的可遍历属性
},
getOwnPropertyDescriptor(target, propKey) {
// 拦截Object.getOwnPropertyDescriptor(proxy, propKey)
// 返回属性的描述对象
},
defineProperty(target, propKey, propDesc) {
// 拦截Object.defineProperty(proxy, propKey, propDesc)、
// Object.defineProperties(proxy, propDescs)
// 返回一个布尔值
},
preventExtensions(target) {
// 拦截Object.preventExtensions(proxy)
// 返回一个布尔值
},
getPrototypeOf(target) {
// 拦截Object.getPrototypeOf(proxy)
// 返回一个对象
},
setPrototypeOf(target, proto) {
// 拦截Object.setPrototypeOf(proxy, proto)
// 返回一个布尔值
},
isExtensible(target) {
// 拦截Object.isExtensible(proxy)
// 返回一个布尔值
},
apply(target, object, args) {
// 拦截 Proxy 实例作为函数调用的操作
// 如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)等
},
construct(target, args) {
// 拦截 Proxy 实例作为构造函数调用的操作
// 如new proxy(...args)
},
});
3.TypeScript 中 Proxy 的声明
interface ProxyHandler<T extends object> {
getPrototypeOf?(target: T): object | null;
setPrototypeOf?(target: T, v: any): boolean;
isExtensible?(target: T): boolean;
preventExtensions?(target: T): boolean;
getOwnPropertyDescriptor?(
target: T,
p: PropertyKey
): PropertyDescriptor | undefined;
has?(target: T, p: PropertyKey): boolean;
get?(target: T, p: PropertyKey, receiver: any): any;
set?(target: T, p: PropertyKey, value: any, receiver: any): boolean;
deleteProperty?(target: T, p: PropertyKey): boolean;
defineProperty?(
target: T,
p: PropertyKey,
attributes: PropertyDescriptor
): boolean;
enumerate?(target: T): PropertyKey[];
ownKeys?(target: T): PropertyKey[];
apply?(target: T, thisArg: any, argArray?: any): any;
construct?(target: T, argArray: any, newTarget?: any): object;
}
interface ProxyConstructor {
revocable<T extends object>(
target: T,
handler: ProxyHandler<T>
): { proxy: T; revoke: () => void };
new <T extends object>(target: T, handler: ProxyHandler<T>): T;
}