proxy 搭配 weakmap 实现 vue3 响应式系统,核心是“读时收集依赖、写时精准触发”,通过 proxy 的 get/set 拦截调用 track/trigger,weakmap 保证内存安全,effect 管理依赖收集与调度,ref 与 reactive 共享同一套依赖逻辑。

用 Proxy 搭配 WeakMap 实现 Vue3 风格的响应式系统,核心在于“读时收集依赖、写时精准触发”,不预遍历、不污染原始对象、内存安全。关键不是堆砌代码,而是理清三件事:谁在监听、监听什么、怎么通知。
Proxy 拦截读写行为,触发依赖链路
Proxy 的 get/set 是响应式的入口。get 时不直接返回值,而是先调用 track(target, key) 记录当前正在执行的副作用函数(如组件渲染函数);set 时则调用 trigger(target, key) 找出所有依赖该属性的函数并执行。
- get 拦截中必须用
Reflect.get()保证原语义,同时支持嵌套访问(如obj.user.name)自动递归 reactive - set 拦截返回
Reflect.set()结果,确保赋值成功,并在变更后触发更新 - 对数组索引赋值(
arr[0] = x)、length 修改、Map/Set 操作等,Proxy 天然可捕获,无需额外 patch
WeakMap 存对象级映射,避免内存泄漏
WeakMap 用原始对象作 key,意味着只要对象被 JS 引擎回收,对应依赖数据(Map → Set)也会自动释放——这正是响应式系统不导致内存泄漏的关键设计。
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 结构是:
targetMap: WeakMap<object map set>>></object> - 第一次访问
obj.count时,若targetMap.get(obj)为空,则新建一个 Map 并存入;再取map.get('count'),为空则新建 Set 并加入当前 effect - 不用 WeakMap 而用普通 Map,会导致对象即使已无引用,其依赖集合仍驻留内存
effect 函数驱动依赖收集与自动调度
effect 就是“带副作用的响应式函数”,它执行时会把自己设为全局活跃 effect(activeEffect),让后续的 get 拦截能知道该往哪塞依赖。
- effect 内部需支持嵌套:用栈(
effectStack)保存上层 effect,退出时恢复activeEffect - 每次 effect 执行前,先清理自己旧的依赖(
cleanup()),防止残留“脏依赖”引发误更新 - 可选加
scheduler参数,把触发逻辑交给队列统一调度(如防抖、合并、异步 microtask)
ref 和 reactive 的统一底层支撑
ref 本质是包装对象({ value }),其 getter/setter 同样走 track/trigger;reactive 则是对目标对象做 Proxy。两者共用同一套 targetMap 和依赖逻辑,只是代理层级不同。
- ref 的响应式靠
Object.defineProperty或 Proxy 包装的 value 属性实现,但内部 track 仍用 targetMap —— ref.value 的 target 就是那个包装对象 - reactive 对象的深层属性(如
state.user.profile.name)首次访问时才递归代理,实现真正的“懒代理”,启动零开销 - toRefs 解构时,每个 ref 都独立 track,所以解构后仍保持响应性
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










