Intro

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

使用 Proxy() 构造函数来创建一个新的 Proxy 对象。 构造函数接收两个必须的参数:

  • target:要创建代理的对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
  • handler:定义了代理的自定义行为的对象。

Example

const target = {
  name: "John Doe",
  age: 30,
};
 
const handler = {
  get: function(target, property) {
    console.log(`Getting property "${property}" from target`);
    return Reflect.get(target, property);
  },
  set: function(target, property, value) {
    console.log(`Setting property "${property}" to "${value}" on target`);
    return Reflect.set(target, property, value);
  },
};
 
const proxy = new Proxy(target, handler);

拦截操作

handler 对象可以包含以下属性,用于拦截对代理对象的各种操作:

  • get:拦截属性读取操作。
  • set:拦截属性赋值操作。
  • has:拦截 in 操作。
  • deleteProperty:拦截 delete 操作。
  • apply:拦截函数调用操作。
  • construct:拦截构造函数调用操作。
  • getOwnPropertyDescriptor:拦截 Object.getOwnPropertyDescriptor 操作。
  • defineProperty:拦截 Object.defineProperty 操作。
  • preventExtensions:拦截 Object.preventExtensions 操作。
  • isExtensible:拦截 Object.isExtensible 操作。
  • ownKeys:拦截 Object.getOwnPropertyNames 和 Object.getOwnPropertySymbols 操作。

Demo

数据验证

const handler = {
  set: function(target, property, value) {
    if (typeof value !== "number") {
      throw new Error("Invalid value: " + value);
    }
 
    return Reflect.set(target, property, value);
  },
};
 
const proxy = new Proxy({}, handler);
 
proxy.age = 30; // 成功
proxy.name = "John Doe"; // 抛出错误

数据格式化

const handler = {
  get: function(target, property) {
    const value = Reflect.get(target, property);
    if (property === "name") {
      return value.toUpperCase();
    }
 
    return value;
  },
};
 
const proxy = new Proxy({ name: "John Doe" }, handler);
 
console.log(proxy.name); // 输出 "JOHN DOE"

权限控制

const handler = {
  get: function(target, property) {
    if (currentUser.hasPermission(property)) {
      return Reflect.get(target, property);
    }
 
    return undefined;
  },
};
 
const proxy = new Proxy(user, handler);
 
console.log(proxy.age); // 成功
console.log(proxy.salary); // undefined

日志记录

const object = {
  "num": 1,
  "str": "Hello World",
  "obj": {
    "x": 5
  }
};
 
const proxiedObject = new Proxy(object, {
  get: (target, key) => {
    console.log("Accessing", key);
    return target[key];
  }
});
 
proxiedObject.num; // 打印: Accessing num