Vue3 响应式原理深度解析
核心机制 - Proxy 代理
- 使用 ES6 Proxy 替代 Vue2 的 Object.defineProperty
- 通过拦截 get/set/deleteProperty 等操作实现响应追踪
const reactive = (target) => new Proxy(target, {
get(obj, key) {
track(obj, key); // 依赖收集
return Reflect.get(obj, key);
},
set(obj, key, value) {
Reflect.set(obj, key, value);
trigger(obj, key); // 触发更新
return true;
}
});
依赖收集与触发
- 使用 WeakMap 建立 target -> key -> effect 的三级映射关系
- effect 函数包裹副作用,自动建立依赖关系
let activeEffect;
function effect(fn) {
activeEffect = fn;
fn();
}
function track(target, key) {
if (activeEffect) {
// 建立 target-key-effect 的映射关系
}
}
function trigger(target, key) {
// 根据映射关系找到对应 effect 执行
}
优化策略对比 Vue2
- 响应式层级扁平化:无需递归转换整个对象
- 惰性触发:仅在访问时收集依赖
- 数组处理优化:直接监听数组索引变化
- 类型推断优化:对 Map/Set 等集合类型支持更好
编译时优化
- PatchFlag 标记动态节点类型
- 静态提升:将静态节点提升到渲染函数外
- 事件监听缓存:缓存事件处理函数
响应式类型区分
- reactive:深响应式转换(对象/数组)
- ref:值类型包装器(支持基本类型)
- shallowRef:浅层响应式包装
- readonly:创建只读代理
// 响应式对象示例 |
响应式系统优势
- 性能提升:初始化速度提升约 40%
- 内存优化:减少约 50% 的内存占用
- 类型支持:更好的 TypeScript 集成
- 动态属性:自动检测新增/删除属性
注意事项
- 避免直接操作原始对象
- 数组操作需使用代理方法
- 解构可能丢失响应式(需使用 toRefs)
- 循环引用需特殊处理
- 异步更新队列优化(自动合并多次更新)
// 正确解构方式
const { count } = toRefs(state);
watchEffect(() => {
console.log(count.value);
});
评论