返回
创建于
状态公开
我们来一步步实现一个简化版 Vue3 响应式系统,用到 WeakMap + Proxy ——
这就是 WeakMap 在框架底层的经典、最强应用场景之一。
🧩 一、设计目标
我们要实现的功能:
✅ 1. 任意对象变为“响应式”(reactive)
✅ 2. 访问属性时自动“收集依赖”
✅ 3. 修改属性时自动“触发更新”
✅ 4. 使用 WeakMap 存储对象 → 属性 → 依赖关系
✅ 5. 自动避免内存泄漏
🧠 二、基本结构示意
1targetMap (WeakMap)
2 └── target (对象)
3 └── depsMap (Map)
4 └── key → Set(effect)解释:
targetMap:WeakMap,用于保存每个“响应式对象”的依赖;depsMap:Map,每个 key 对应一组副作用函数(Set);- 当读取属性时 → 记录依赖;
- 当修改属性时 → 触发依赖。
⚙️ 三、完整实现代码(可直接运行)
1// 🌱 存储所有对象依赖关系
2const targetMap = new WeakMap();
3
4// 当前正在执行的副作用函数
5let activeEffect = null;
6
7// 收集依赖
8function track(target, key) {
9 if (!activeEffect) return;
10
11 let depsMap = targetMap.get(target);
12 if (!depsMap) {
13 depsMap = new Map();
14 targetMap.set(target, depsMap);
15 }
16
17 let dep = depsMap.get(key);
18 if (!dep) {
19 dep = new Set();
20 depsMap.set(key, dep);
21 }
22
23 dep.add(activeEffect);
24}
25
26// 触发依赖更新
27function trigger(target, key) {
28 const depsMap = targetMap.get(target);
29 if (!depsMap) return;
30 const dep = depsMap.get(key);
31 if (dep) {
32 dep.forEach(effect => effect());
33 }
34}
35
36// 创建响应式对象
37function reactive(target) {
38 return new Proxy(target, {
39 get(obj, key, receiver) {
40 track(obj, key);
41 return Reflect.get(obj, key, receiver);
42 },
43 set(obj, key, value, receiver) {
44 const result = Reflect.set(obj, key, value, receiver);
45 trigger(obj, key);
46 return result;
47 }
48 });
49}
50
51// 定义副作用函数
52function effect(fn) {
53 const wrapper = () => {
54 activeEffect = wrapper;
55 fn();
56 activeEffect = null;
57 };
58 wrapper();
59}
60
61// 🌟 使用示例
62const state = reactive({ count: 0, msg: 'hello' });
63
64effect(() => {
65 console.log('count 改变了 →', state.count);
66});
67
68state.count++; // 输出:count 改变了 → 1
69state.count++; // 输出:count 改变了 → 2🧩 四、解释关键点
| 模块 | 作用 |
|---|---|
targetMap | 使用 WeakMap 存放所有响应式对象 |
Map(内部) | 记录每个属性的依赖集合 |
Set(内部) | 依赖函数集合(无重复) |
track() | 在读取属性时注册依赖 |
trigger() | 在修改属性时触发依赖 |
WeakMap 的好处 | 当对象被释放时,对应依赖自动清除,不会内存泄漏 |
🌳 五、WeakMap 的意义
这一点非常关键:
-
targetMap是一个 WeakMap; -
当
state(被代理对象)不再被引用时:- 它会被垃圾回收;
targetMap中的记录自动消失;- 无需手动清理依赖;
- 不会引起内存泄漏。
🔥 这正是 Vue3、MobX、SolidJS 等框架使用
WeakMap的核心原因。
🧱 六、扩展:嵌套对象支持(递归代理)
如果我们要让内部对象也响应式,只要在 get 时递归代理:
1function reactive(target) {
2 return new Proxy(target, {
3 get(obj, key, receiver) {
4 const result = Reflect.get(obj, key, receiver);
5 track(obj, key);
6 if (typeof result === 'object' && result !== null) {
7 return reactive(result); // 递归代理
8 }
9 return result;
10 },
11 set(obj, key, value, receiver) {
12 const result = Reflect.set(obj, key, value, receiver);
13 trigger(obj, key);
14 return result;
15 }
16 });
17}🧩 七、最终效果演示
1const appState = reactive({
2 user: { name: 'Alice', age: 18 },
3 count: 0
4});
5
6effect(() => {
7 console.log(`用户:${appState.user.name}, 年龄:${appState.user.age}`);
8});
9
10appState.user.name = 'Bob'; // 自动触发 effect输出:
1用户:Alice, 年龄:18
2用户:Bob, 年龄:18🧠 八、总结
| 技术 | 作用 |
|---|---|
| WeakMap | 保存对象 → 属性依赖关系,自动清理 |
| Proxy | 拦截 get/set |
| effect() | 注册依赖 |
| track / trigger | 实现依赖收集与触发 |
| 优点 | 自动化依赖追踪 + 无内存泄漏 |