2025.09.16
基础骨架:WeakMap 实现三层依赖存储
🧐 挑战回顾
在 reactive 模块中,我们面临的核心挑战是如何为对象的每个属性维护一个独立的 Dep(依赖集合),同时确保不污染原始目标对象
target。
ref依赖存储:Dep直接挂载到Ref实例上reactive依赖存储: 多属性, 需要建立一个全局的映射表 来存储target -> key -> Dep这种层级关系
🔑 核心解决方案
选择使用 WeakMap 作为顶层容器,来实现目标对象与依赖图的关联。
const targetMap = new WeakMap() // 全局依赖存储容器
为什么使用 WeakMap
理想型选择, 它提供了 非侵入性和内存管理 双重优势:
- 健必须是对象:
WeakMap的key只能是对象, 天然适用于响应式对象target作为键 - 弱引用:
WeakMap对 键 的引用是 弱引用。如果没有其他变量引用target, 就会被垃圾回收清理掉, 避免内存泄露
🧱 三层依赖存储结构

| 层级 | 数据结构 | Key | value | 职责 |
|---|---|---|---|---|
| 1 | target (WeakMap) | 原始 target 对象 | depsMap (Map) | 将响应式对象映射到其属性的依赖集合。 |
| 2 | depsMap (Map) | 属性 key (字符串) | Dep 实例 | 将属性名映射到该属性的 Dep 实例 |
| 3 | Dep 实例 | subs / subsTail | 存储所有依赖与该属性的 effect |
// 逻辑视图
// targetMap = WeakMap {
// { a: 1, b: 2 } => Map {
// 'a' => Dep { subs: link1 -> link3... }, // 管理属性 a 的依赖
// 'b' => Dep { subs: link2 -> link4... } // 管理属性 b 的依赖
// }
// }
⚙️ 依赖收集(track)的实现
function track(target: object, key: PropertyKey) {
if (!activeSub)
return
// 1. 查找 target 对应的 depsMap
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap) // 首次访问:创建并存储 Map
}
// 2. 查找 key 对应的 Dep
let dep = depsMap.get(key)
if (!dep) {
dep = new Dep()
depsMap.set(key, dep) // 首次访问该 key:创建并存储 Dep
}
// 3. 关联:将当前的 effect (activeSub) 链接到 Dep
link(dep, activeSub)
}
📢 派发更新(trigger)的实现
function trigger(target: object, key: PropertyKey) {
// 1. 查找 target 对应的 depsMap
const depsMap = targetMap.get(target)
if (!depsMap)
return // target 没有依赖,直接返回
// 2. 查找 key 对应的 Dep
const dep = depsMap.get(key)
if (!dep)
return // key 没有依赖,直接返回
// 3. 触发更新:通知所有订阅者重新执行
if (dep) {
propagate(dep.subs)
}
}
🧪 测试一下
<script type="module">
// ... imports ...
const state = reactive({ a: 0 })
effect(() => {
console.log('state.a ==> ', state.a) // 收集 state.a 的依赖
})
setTimeout(() => {
state.a = 2 // 触发 state.a 的 Dep 通知
}, 1000)
</script>
- 初始化的时候 打印
state.a ==> 0 - 1 秒后 打印
state.a ==> 2