Vue3 的响应式系统源码级 Proxy 与 Reflect 协同工作原理
字数 808 2025-11-16 02:38:06
Vue3 的响应式系统源码级 Proxy 与 Reflect 协同工作原理
题目描述
Vue3 的响应式系统基于 Proxy 和 Reflect API 实现,通过拦截对象操作实现依赖收集和触发更新。需要深入理解 Proxy 的陷阱函数如何与 Reflect 方法协同工作,以及这种设计如何解决 Vue2 Object.defineProperty 的局限性。
核心原理解析
-
Proxy 的基本拦截机制
Proxy 允许创建一个对象的代理,通过定义陷阱函数(trap)来拦截对目标对象的操作。Vue3 主要使用以下陷阱:get: 拦截属性读取set: 拦截属性设置has: 拦截in操作符deleteProperty: 拦截delete操作
-
Reflect 的反射调用作用
Reflect 提供与 Proxy 陷阱对应的方法,用于执行对象的默认行为。其核心价值:- 保持 this 指向正确:
Reflect.get(target, key, receiver)的第三个参数确保在访问器属性中this指向代理对象而非原对象 - 提供操作返回值:如
Reflect.set返回布尔值表示操作是否成功
- 保持 this 指向正确:
-
具体协同工作流程
const reactive = (target) => { return new Proxy(target, { get(target, key, receiver) { // 使用 Reflect 执行默认获取行为 const res = Reflect.get(target, key, receiver) // 依赖收集跟踪 track(target, key) return isObject(res) ? reactive(res) : res // 深层代理 }, set(target, key, value, receiver) { const oldValue = target[key] // 通过 Reflect.set 执行设置操作 const success = Reflect.set(target, key, value, receiver) if (success && oldValue !== value) { // 触发依赖更新 trigger(target, key) } return success } }) } -
解决 Vue2 的局限性
- 动态属性增删:Proxy 天然支持对新增属性的拦截,无需
Vue.set - 数组索引修改:直接通过
arr[0] = value可触发响应式 - 嵌套对象自动化代理:在 get 陷阱中递归返回代理对象
- 动态属性增删:Proxy 天然支持对新增属性的拦截,无需
-
Receiver 参数的关键作用
当代理对象有继承关系时,receiver 确保操作正确传递:const parent = { a: 1 } const child = Object.create(parent) const proxy = new Proxy(child, { get(target, key, receiver) { // receiver 始终指向最外层的代理对象 console.log(receiver === proxy) // true return Reflect.get(target, key, receiver) } })
设计优势总结
Proxy + Reflect 的组合实现了真正的懒代理机制(按需代理深层属性),避免了 Vue2 初始化时的递归性能损耗,同时提供了更完善的拦截能力,为 Vue3 的响应式系统奠定了坚实基础。