外观
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 就是这么做的。 ===比较的是代理和原对象,它们不相等。