Proxy 与 Reflect:响应式系统的基石
Proxy 与 Reflect:响应式系统的基石
Vue 3 响应式的底层是 Proxy,而规范的 Proxy 写法离不开 Reflect。把两者一起讲透。
Proxy:对象操作的拦截器
Proxy 在目标对象外套一层代理,可拦截对象的几乎所有底层操作——不是只有读写:
const p = new Proxy(user, {
get(target, key, receiver) {
console.log('读取', key)
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
console.log('设置', key)
return Reflect.set(target, key, value, receiver)
},
deleteProperty(target, key) {
console.log('删除', key)
return Reflect.deleteProperty(target, key)
},
has(target, key) { /* key in obj 的拦截 */ },
ownKeys(target) { /* Object.keys / for...in 的拦截 */ },
})
可拦截的陷阱(trap)有 13 种,包括 apply(函数调用)、construct(new)、getPrototypeOf 等。
为什么必须用 Reflect
Reflect API 与 Proxy 陷阱一一对应,把对象底层操作变成函数调用。两个关键理由:
1. receiver 传递保证正确的 this 与响应式穿透
receiver 指向"正在操作的代理对象"。访问嵌套属性时,如果直接 return target[key],getter 内的 this 指向原始对象而非代理——深层响应式就断了。Reflect.get(target, key, receiver) 让 getter 中的 this 保持为代理,嵌套访问才能持续触发拦截(这也是 Vue 3 用 Reflect 的核心原因)。
2. 操作的返回值语义
Reflect.set/deleteProperty 返回布尔值表示是否成功(严格模式下手动赋值失败会抛异常,Reflect 则安静返回 false),陷阱中可以正确决定后续行为,且不会意外抛错。
与 defineProperty 的本质区别
- defineProperty 劫持单个属性,Proxy 代理整个对象
- Proxy 天然拦截新增属性、删除、数组下标、length
- Proxy 无法 polyfill;Reflect 是 ES6 内置
最小响应式 Demo
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key)
const res = Reflect.get(target, key, receiver)
return res !== null && typeof res === 'object' ? reactive(res) : res
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver)
trigger(target, key)
return res
},
})
}
这就是 Vue 3 reactive 的骨架。理解了 Proxy 13 个陷阱和 Reflect 的 receiver 语义,再读响应式源码会非常顺畅。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

评论0 条
还没有评论,来抢沙发~