什么是Proxy,理解并使用

在 JavaScript 中,Proxy 是一个强大的原生对象,引入于 ES6(ECMAScript 2015),它允许你创建一个代理对象,用来拦截和自定义对目标对象的操作(如属性访问、赋值、函数调用等)。简单来说,Proxy 就像一个“中间人”,在你和目标对象之间加了一层,可以让你控制对象的行为。


什么是 Proxy

Proxy 是一个构造函数,通过它可以创建一个代理对象。它的基本语法是:

  • target:被代理的目标对象,可以是对象、数组、函数等。
  • handler:一个对象,定义了拦截行为的方法(称为“陷阱”,traps),比如 getsethas 等。
  • proxy:返回的代理对象,替代了直接操作 target

通过 handler 定义的陷阱,你可以自定义目标对象的行为,比如:

  • 读取属性时做什么(get
  • 设置属性时做什么(set
  • 检查属性是否存在时做什么(has

怎么理解 Proxy

你可以把 Proxy 想象成一个“门卫”或者“过滤器”:

  • 没有 Proxy 时,你直接操作对象,就像直接走进房间拿东西。
  • 有了 Proxy,相当于房间门口多了个门卫,每次你想拿东西(访问属性)或放东西(赋值),门卫都会先检查、记录,甚至可以阻止你。

这个“门卫”不会改变原始对象,而是通过代理对象提供一个可控的接口。

类比示例:

假设有一个普通对象:

如果加了 Proxy,你可以控制访问和修改:


怎么用 Proxy

Proxy 的用法是通过定义 handler 中的陷阱来实现自定义行为。以下是一些常见用法和示例:

1. 拦截属性访问(get

  • 用途:监控属性读取,或者为不存在的属性提供默认值。
  • 示例:

2. 拦截属性赋值(set

  • 用途:验证赋值的数据,或者禁止某些操作。
  • 示例:

3. 拦截属性检查(has

  • 用途:自定义 in 操作符的行为。
  • 示例:

4. 拦截函数调用(apply

  • 用途:代理函数,添加额外的逻辑。
  • 示例:

常用的陷阱(Traps)

Proxy 支持多种陷阱,这里列出几个常用的:

  • get(target, prop, receiver):拦截属性读取。
  • set(target, prop, value, receiver):拦截属性赋值。
  • has(target, prop):拦截 in 操作。
  • deleteProperty(target, prop):拦截 delete 操作。
  • apply(target, thisArg, args):拦截函数调用。
  • construct(target, args):拦截 new 操作。

完整列表可以在 MDN Proxy 文档 查看。


在 Vue 3 中的应用

Vue 3 的响应式系统大量依赖 Proxy。它通过代理对象来追踪数据的变化:

  • 当你访问一个响应式对象的属性时(get),Vue 收集依赖。
  • 当你修改属性时(set),Vue 触发更新。
    例如:

Vue 用 Proxy 替代了 Vue 2 的 Object.defineProperty,因为 Proxy 可以拦截更多操作(如数组方法、动态属性),性能和功能更强大。


注意事项

  1. 不可代理私有字段Proxy 无法拦截以 # 开头的私有字段,因为它们不走 getter/setter。
  2. 性能开销:代理会增加一些计算开销,不适合对性能敏感的场景。
  3. 原始对象保持不变Proxy 不会修改 target,只是提供了一个代理层。

总结

  • 是什么Proxy 是一个拦截对象操作的工具。
  • 怎么理解:像一个可编程的中间层,控制对目标对象的访问。
  • 怎么用:通过 new Proxy(target, handler) 创建,用陷阱自定义行为。