Skip to content

Proxy 能拦截什么? ​

Proxy 包住一个对象,在读取、写入、删除、枚举等操作发生时执行你的函数。Vue 3 的响应式就是用它收集依赖和触发更新。它拦截的是操作,不是把对象变成另一个类型。

原理 ​

js
const user = { name: "a" }
const proxy = new Proxy(user, {
  get(target, key, receiver) {
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    return Reflect.set(target, key, value, receiver)
  }
})

get、set 要配合 Reflect,并把 receiver 传进去,这样继承时原型上的 getter 里的 this 仍是子对象。set 必须返回布尔值,严格模式下返回 false 会抛错。

其他常用陷阱:has(in)、deleteProperty、ownKeys。函数对象还可以用 apply 和 construct。

代理不到的事:对象自身的内部槽、已经拿出去的原始引用。外部如果还握着 user 而不是 proxy,直接改 user 不会进陷阱。

追问 ​

和 Object.defineProperty 比呢?

defineProperty 要预先知道键,监听不到新增和删除,数组下标也麻烦。Proxy 可以拦截这些操作,而且不用先遍历所有键。见 Vue 响应式。

代理有什么成本?

每次读写都走 JavaScript 函数,热路径上比裸对象慢。只包需要观察的状态,不要把巨大的只读配置也套进去。

易错点 ​

  • set 忘了 return true,严格模式赋值会失败。
  • 代理不是深的。嵌套对象要在 get 时再包一层,Vue 就是这么做的。
  • === 比较的是代理和原对象,它们不相等。

相关 ​