Vue3 的响应式系统源码级 reactive 的实现原理与深层响应式转换机制
字数 675 2025-11-21 23:14:24
Vue3 的响应式系统源码级 reactive 的实现原理与深层响应式转换机制
题目描述
Vue3 的 reactive 函数是如何基于 Proxy 实现深层响应式的?其核心实现机制包括依赖收集、触发更新、深层代理转换等关键环节。理解 reactive 的实现原理需要深入分析 Proxy 拦截器设计、Reflect 的应用、嵌套对象处理等细节。
实现原理详解
1. reactive 函数的基本结构
function reactive(target) {
// 只对对象类型进行响应式转换
if (!isObject(target)) return target
// 避免重复代理:如果已经是响应式对象,直接返回
if (target[ReactiveFlags.RAW]) return target
// 查找已有代理(避免重复创建)
const existingProxy = proxyMap.get(target)
if (existingProxy) return existingProxy
// 创建响应式代理
const proxy = new Proxy(target, baseHandlers)
proxyMap.set(target, proxy) // 缓存代理关系
return proxy
}
2. Proxy 拦截器(baseHandlers)的核心设计
const baseHandlers = {
get(target, key, receiver) {
// 1. 访问 RAW 属性时返回原始对象
if (key === ReactiveFlags.RAW) return target
// 2. 依赖收集:建立响应式关联
track(target, key)
// 3. 获取属性值
const res = Reflect.get(target, key, receiver)
// 4. 深层响应式转换:如果值是对象,递归转换为响应式
if (isObject(res)) {
return reactive(res)
}
return res
},
set(target, key, value, receiver) {
// 1. 获取旧值用于比较
const oldValue = target[key]
// 2. 执行赋值操作
const result = Reflect.set(target, key, value, receiver)
// 3. 触发更新:只有值真正改变时才触发
if (hasChanged(value, oldValue)) {
trigger(target, key)
}
return result
},
has(target, key) {
track(target, key)
return Reflect.has(target, key)
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key)
const result = Reflect.deleteProperty(target, key)
if (hadKey && result) {
trigger(target, key)
}
return result
},
ownKeys(target) {
track(target, ITERATE_KEY) // 迭代操作的特殊键
return Reflect.ownKeys(target)
}
}
3. 深层响应式转换机制
- 惰性代理策略:只有在实际访问对象属性时才会进行深层代理转换
- 递归时机:在 get 拦截器中检测属性值,如果是对象则递归调用 reactive
- 缓存优化:通过 proxyMap 缓存已代理对象,避免重复代理
// 深层响应式转换示例
const obj = reactive({
level1: {
level2: {
value: 1
}
}
})
// 访问过程触发深层代理:
// 1. 访问 obj.level1 → 触发 get 拦截器
// 2. 发现 level1 是对象 → 返回 reactive({ level2: { value: 1 } })
// 3. 访问 obj.level1.level2 → 再次触发 get 拦截器
// 4. 返回 reactive({ value: 1 })
4. 依赖收集(track)的实现细节
// 全局依赖存储结构
const targetMap = new WeakMap() // target -> key -> dep
function track(target, key) {
if (!activeEffect) return // 没有活跃的 effect,直接返回
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}
dep.add(activeEffect) // 建立依赖关系
activeEffect.deps.push(dep) // 反向记录,用于清理
}
5. 触发更新(trigger)的完整流程
function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const effects = new Set()
// 收集与 key 相关的依赖
if (key !== void 0) {
const dep = depsMap.get(key)
dep && dep.forEach(effect => effects.add(effect))
}
// 处理数组长度变化等特殊情况
if (key === 'length' && isArray(target)) {
depsMap.forEach((dep, key) => {
if (key === 'length' || key >= target.length) {
dep.forEach(effect => effects.add(effect))
}
})
}
// 执行所有收集到的 effect
effects.forEach(effect => {
if (effect.options.scheduler) {
effect.options.scheduler(effect) // 调度执行
} else {
effect() // 直接执行
}
})
}
6. 特殊边界情况处理
- 数组方法重写:push/pop/shift 等方法需要特殊处理,避免不必要的更新触发
- 原型链访问:正确处理继承属性的响应式
- Symbol 属性:避免内部 Symbol 属性被响应式化
- 循环引用:通过缓存机制避免无限递归
总结
Vue3 的 reactive 实现基于 Proxy 的拦截能力,通过 get/set 等拦截器实现依赖收集和更新触发。其深层响应式采用惰性代理策略,在属性访问时动态转换嵌套对象。整个系统通过 WeakMap/Map/Set 构建高效的数据结构来管理依赖关系,实现了精确的更新触发和优秀的性能表现。