proxy

1.proxy 简介

Proxy 是 ECMAScript 6(ES6)引入的一种元编程(metaprogramming)特性,它允许你创建对象的代理,以拦截和自定义对象上的基本操作。通过 Proxy,你可以监视、修改或拦截对象的属性访问、属性赋值、属性删除,以及其他一些操作,如函数调用、遍历等。Proxy 的主要用途包括:

  1. 属性访问拦截: 你可以拦截属性的读取操作,允许你在属性被访问时执行自定义的操作。

  2. 属性赋值拦截: 你可以拦截属性的写入操作,允许你在属性被修改时执行自定义的操作。

  3. 属性删除拦截: 你可以拦截属性的删除操作,允许你在属性被删除时执行自定义的操作。

  4. 函数调用拦截: 你可以拦截对象上的函数调用,允许你在函数被调用时执行自定义的操作。

  5. 遍历拦截: 你可以拦截对象的遍历操作,允许你自定义对象的遍历行为。

下面是一个更详细的示例,演示了 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;
}
Contributors: masecho