Skip to content

代理

ES6(ECMAScript 2015)引入的Proxy对象允许你创建一个代理对象,它可以作为访问目标对象的中介。通过Proxy,你可以拦截并自定义基本操作的行为,如属性查找、赋值、枚举、函数调用等。这为开发者提供了强大的能力来扩展对象的行为,实现诸如数据验证、日志记录、私有属性等功能。

创建 Proxy

要创建一个代理,你需要使用Proxy构造函数,并传入两个参数:目标对象(target)和处理器对象(handler)。处理器对象包含了一些方法,这些方法对应着可以被拦截的操作。

javascript
let target = {};
let handler = {
  get: function (obj, prop) {
    return prop in obj ? obj[prop] : 37;
  },
};

let proxy = new Proxy(target, handler);
console.log(proxy.name); // 输出: 37
target.name = "Alice";
console.log(proxy.name); // 输出: Alice

在这个例子中,如果尝试访问proxy对象上不存在的属性,则返回默认值37

常见的处理器方法

get()

拦截对对象属性的读取操作。

javascript
let handlerGet = {
  get: function (obj, prop, receiver) {
    console.log(`Getting ${prop}`);
    return Reflect.get(...arguments);
  },
};
let proxyGet = new Proxy({ name: "Alice" }, handlerGet);
console.log(proxyGet.name); // 控制台输出: Getting name \n Alice

set()

拦截对对象属性的设置操作。

javascript
let handlerSet = {
  set: function (obj, prop, value, receiver) {
    if (typeof value === "string") {
      return Reflect.set(obj, prop, value.toUpperCase(), receiver);
    } else {
      return Reflect.set(...arguments);
    }
  },
};
let proxySet = new Proxy({}, handlerSet);
proxySet.name = "Alice";
console.log(proxySet.name); // 输出: ALICE

has()

拦截in操作符。

javascript
let handlerHas = {
  has: function (obj, prop) {
    if (prop == "secret") return false;
    return prop in obj;
  },
};
let proxyHas = new Proxy({ name: "Alice", secret: "hidden" }, handlerHas);
console.log("name" in proxyHas); // 输出: true
console.log("secret" in proxyHas); // 输出: false

deleteProperty()

拦截delete操作。

javascript
let handlerDelete = {
  deleteProperty: function (obj, prop) {
    console.log(`Deleting ${prop}`);
    return Reflect.deleteProperty(...arguments);
  },
};
let proxyDelete = new Proxy({ name: "Alice" }, handlerDelete);
delete proxyDelete.name; // 控制台输出: Deleting name
console.log("name" in proxyDelete); // 输出: false

应用场景

  • 数据验证:可以在设置属性值之前进行数据验证。
  • 日志记录:在获取或设置属性值时记录日志信息。
  • 私有属性:通过代理隐藏某些属性,使其对外不可见。
  • 依赖追踪:用于观察对象的变化,在响应式系统中非常有用,比如 Vue.js 中的反应性系统。

结合Reflect使用

Proxy通常与Reflect一起使用,以执行默认行为。例如,在处理set操作时,可以通过Reflect.set()确保属性能够正常设置。

javascript
let target = { name: "Alice" };
let handler = {
  set: function (obj, prop, value, receiver) {
    if (value.length > 2) {
      return Reflect.set(obj, prop, value, receiver);
    } else {
      console.log("Too short");
      return false; // 表示设置失败
    }
  },
};

let proxy = new Proxy(target, handler);
proxy.name = "Jo"; // 控制台输出: Too short
proxy.name = "John";
console.log(proxy.name); // 输出: John

通过Proxy,JavaScript 提供了一种灵活且强大的方式来定制对象的基本操作,极大地增强了代码的可扩展性和维护性。

Released under the MIT License.