Vue计算属性自动更新靠响应式系统精准建立“谁用了谁、谁变了通知谁”的映射关系,首次求值时标记活跃Watcher并静默收集所有被访问的响应式字段依赖,数据变更时标记dirty并延迟至微任务重算。

Vue 计算属性的自动更新,靠的不是轮询或猜测,而是响应式系统在数据读取和写入时精准建立的“谁用了谁、谁变了通知谁”的映射关系。它不依赖你声明依赖列表,而是在 getter 执行过程中同步捕获所有被访问的响应式字段。
依赖怎么被悄悄记下来的?
计算属性首次求值时,Vue 会临时把当前计算任务标记为“活跃观察者”。此时只要读取一个响应式字段(比如 user.name 或 list[0].id),它的 getter 就会把当前这个计算任务存进自己的依赖池里。这个过程是递归且静默的:
- 嵌套属性如 profile.address.city,只要 profile 是 reactive 的,就能被完整追踪
- 数组索引访问(items[2].title)和方法调用中涉及的响应式读取(items.filter(x => x.active))也会被纳入依赖
- 普通对象、Date.now()、Math.random()、localStorage 读取等非响应式值,不会留下任何依赖记录
数据变了,谁来动?怎么动?
当某个响应式字段被赋新值,它的 setter 会立刻遍历自己绑定的所有依赖(也就是之前收集到的那些 Watcher),并触发它们的更新流程。对计算属性来说,这并不等于马上重跑函数:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 它只是把内部标记设为 dirty = true,表示“结果已过期”
- 真正的重新计算被推迟到下一个微任务(nextTick),与其他更新批量处理,避免重复执行
- 如果同一计算属性被模板、其他 computed 或 watch 多次引用,也只维护一个 Watcher,共享缓存与更新逻辑
为什么改了数据却没更新?常见断点在哪?
所谓“不更新”,往往是因为依赖根本没被收集上。典型情况包括:
立即学习“前端免费学习笔记(深入)”;
- 在 Promise.then、setTimeout 或事件回调里才读取响应式数据——此时 getter 已结束,依赖收集早已关闭
- 用 v-if 或提前 return 跳过了某字段的访问,那个字段就不会成为依赖
- 直接操作未被 reactive 包裹的普通对象,或通过字符串 key 动态访问(如 obj[key])但 key 本身不是响应式
- Vue 2 中对数组索引赋值(arr[0] = x)或修改 length,需用 Vue.set;Vue 3 的 Proxy 已支持大部分场景
复杂逻辑该怎么组织才稳?
一个计算属性里塞太多 if/else、多层嵌套或混合副作用,容易绕过依赖追踪,也难调试。更可靠的做法是分层拆解:
- 把基础派生字段单独抽成计算属性,例如 filteredItems、hasError、isReady
- 高层计算属性只组合这些中间结果,比如 displayText 基于 filteredItems.length 和 isReady
- 若必须动态依赖(如根据 prop.key 读取不同字段)或需要副作用(发请求、改 DOM),改用 watchEffect 更合适

















