Vue3 的响应式模块本质是一个:
参数化的 Proxy 工厂系统
核心目标只有两件事:
-
分类处理不同类型目标对象
-
保证代理实例的唯一性与可复用
整个系统围绕一个核心函数展开:
createReactiveObject
所有响应式 API 都只是它的参数组合。
一、整体架构
reactivity 的核心结构:
工厂函数 → createReactiveObject → Proxy → 全局缓存
特点:
-
全局统一拦截策略
-
分类 handler 体系
-
WeakMap 缓存代理实例
-
防止 Proxy 嵌套
-
原始对象可追溯
可以理解为:
一个可配置的 Proxy 生成引擎
二、四大工厂函数
Vue 提供 4 个顶层 API,本质是参数不同:
1. reactive —— 深度响应式
reactive(target)
使用:
-
mutableHandlers
-
mutableCollectionHandlers
-
reactiveMap
递归代理所有嵌套对象。
2. shallowReactive —— 浅响应式
shallowReactive(target)
只代理第一层属性:
-
shallowReactiveHandlers
-
shallowCollectionHandlers
-
shallowReactiveMap
适合大对象性能优化。
3. readonly —— 深度只读
readonly(target)
创建不可变视图:
-
readonlyHandlers
-
readonlyCollectionHandlers
-
readonlyMap
仍然追踪依赖,但禁止写入。
4. shallowReadonly —— 浅只读
shallowReadonly(target)
只读 + 浅代理组合。
三、核心函数:createReactiveObject
签名:
createReactiveObject(
target,
isReadonly,
baseHandlers,
collectionHandlers,
proxyMap
)
这是 Vue3 响应式的真正入口。
它解决 4 个关键问题:
1. 目标对象分类
Vue 把对象分为两大类:
普通对象类
-
Object
-
Array
集合类
-
Map
-
Set
-
WeakMap
-
WeakSet
集合类型需要特殊 handler,因为它们不是属性访问模型,而是方法驱动模型。
2. Handler 分类体系
结合三个维度:
-
深 / 浅
-
只读 / 可变
-
对象 / 集合
一共形成 8 类拦截器:
Object / Array
-
mutableHandlers
-
readonlyHandlers
-
shallowReactiveHandlers
-
shallowReadonlyHandlers
Collection
-
mutableCollectionHandlers
-
readonlyCollectionHandlers
-
shallowCollectionHandlers
-
shallowReadonlyCollectionHandlers
这是其中拦截处理是关键,后面再更。
3. 代理缓存机制
Vue 为每种模式维护一个 WeakMap:
reactiveMap
shallowReactiveMap
readonlyMap
shallowReadonlyMap
规则:
一个原始对象只对应一个 Proxy
流程:
-
创建前先查缓存
-
命中直接返回
-
未命中才创建新 Proxy
好处:
-
避免重复代理
-
保持引用一致性
-
节省内存
4. 防止 Proxy 嵌套
Vue 通过内部标志位控制:
ReactiveFlags.RAW
ReactiveFlags.IS_REACTIVE
ReactiveFlags.IS_READONLY
关键机制:
target[RAW] → 永远指向原始对象
所以:
reactive(reactive(obj))
仍然返回同一个 Proxy。
但允许:
readonly(reactive(obj))
创建只读副本。
这是刻意设计的“对称性规则”。
四、工具函数体系
这些函数是对响应式状态的 introspection(内省能力)。
isReactive
判断是否响应式对象:
-
如果是 readonly
→ 判断原始对象 -
否则直接读标志位
isReadonly
读取:
ReactiveFlags.IS_READONLY
isShallow
读取:
ReactiveFlags.IS_SHALLOW
isProxy
判断是否是 Vue 代理对象:
ReactiveFlags.RAW in target
toRaw
递归取出原始对象:
proxy → raw → raw → raw
直到不是 Proxy。
markRaw
跳过代理:
target[SKIP] = true
createReactiveObject 会直接忽略它。
用于:
-
第三方库实例
-
DOM 对象
-
性能敏感数据
toReactive / toReadonly
语义化封装:
toReactive(x) → reactive(x)
toReadonly(x) → readonly(x)
主要用于内部统一流程。