第六章 JavaScript标准库 6.13 Proxy

69 阅读3分钟

6.13 Proxy

Proxy 是 ES6 中新增的一个内置构造函数,用于生成一个对象的代理对象,它接收两个参数:

  • target:被代理的目标对象,可以是任何类型的对象,包括函数、数组等等。
  • handler:一个对象,用来自定义代理行为的函数,它包含了一组拦截器的属性,用于拦截对目标对象的各种操作。 Proxy 可以被认为是在目标对象和外界之间建立了一道拦截层,所有对目标对象的访问都要经过这道拦截层,从而达到对目标对象的控制和管理的目的。 下面展示一个简单的例子来说明如何使用 Proxy。 假设有一个对象 person,其中有两个属性 name 和 age。我们希望在读取和设置这两个属性时,都做一些额外的操作,比如在读取时添加日志记录,设置时检查数据类型等等。 使用 Proxy,我们可以创建一个拦截器对象 personProxy,在该对象上定义对应的拦截操作来达到上述目的。具体实现代码如下:
const person = {
  name: 'John',
  age: 30,
};

const personProxy = new Proxy(person, {
  get(target, propKey) {
    console.log(`Getting value of ${propKey}: ${target[propKey]}`);
    return target[propKey];
  },
  set(target, propKey, value) {
    if (propKey === 'age' && typeof value !== 'number') {
      console.error(`Invalid value type for ${propKey}: ${value}`);
      return false;
    }
    console.log(`Setting ${propKey} to ${value}`);
    target[propKey] = value;
    return true;
  },
});

console.log(personProxy.name); // Getting value of name: John, 输出 John
personProxy.age = '30'; // Invalid value type for age: 30, 不会更新 person 的 age 属性
personProxy.age = 35; // Setting age to 35, 更新 person 的 age 属性为 35

在这个例子中,我们定义了 personProxy 对象,它是 person 对象的代理。当我们通过 personProxy 读取 name 和 age 属性时,会触发代理对象上的 get 拦截器,输出读取属性的信息并返回对应的属性值;当我们设置 age 属性时,会触发代理对象上的 set 拦截器,根据属性值类型进行检查,如果类型不正确则输出错误信息并返回 false,否则输出设置属性的信息并更新 person 对象的对应属性。 上面例子中的 get 和 set 就叫做拦截器,handler 对象上一共可以有 13 种拦截器,下面分别介绍他们的作用。 1 get(target, propKey, receiver):拦截对象属性的读取,比如 proxy.foo 和 proxy['foo']。 2 set(target, propKey, value, receiver):拦截对象属性的设置,比如 proxy.foo = v 或 proxy['foo'] = v,返回一个布尔值。 3 has(target, propKey):拦截 propKey in proxy 的操作,返回一个布尔值。 4 deleteProperty(target, propKey):拦截 delete proxy[propKey]的操作,返回一个布尔值。 5 ownKeys(target):拦截 Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个数组。该方法返回目标对象所有自身属性的属性名,而 Object.keys() 的返回结果仅包括目标对象自身的可枚举属性。 6 getOwnPropertyDescriptor(target, propKey):拦截 Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。 7 defineProperty(target, propKey, propDesc):拦截 Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。 8 isExtensible(target): 拦截 Object.isExtensible 操作,返回一个布尔值。 9 preventExtensions(target):拦截 Object.preventExtensions(proxy),返回一个布尔值。 10 getPrototypeOf(target):拦截 Object.getPrototypeOf(proxy),返回一个对象。 11 setPrototypeOf(target, proto):拦截 Object.setPrototypeOf(proxy, proto),返回一个布尔值。 12 apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如 proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。 13 construct(target, args, newTarget):拦截 Proxy 实例作为构造函数调用的操作,比如 new proxy(...args)。