computed 缓存失效本质是 dirty 标志置为 true,而非清除缓存;仅当下次读取时检测到 dirty 为 true 才重算并更新 value 和 dirty = false。

Computed 缓存失效,不是“缓存被清空”,而是“缓存标记为过期”,等下一次读取时才真正重新计算。
缓存失效的本质是 dirty 标志位变化
Vue 内部为每个 computed 属性维护一个 惰性 watcher,它有三个关键字段:dirty(是否需重算)、value(缓存结果)、deps(依赖列表)。初始时 dirty = true,首次访问 getter 会执行计算、保存结果,并将 dirty = false。之后只要依赖没变,就直接返回 value。
当任一依赖的响应式数据被修改(比如 this.count++),Vue 的响应式系统会通知该 computed 的 watcher,将其 dirty 设为 true——此时缓存并未清除,只是“作废标记”已打上。
只有当下一次代码中读取这个 computed 属性(例如在模板中渲染、或 JS 中访问 this.fullName)时,Vue 才检查 dirty === true,触发 getter 重执行,并更新 value 和 dirty = false。
什么才算“依赖项发生改变”
必须是 被追踪的响应式属性本身被赋值,且赋值导致其 __ob__.dep.notify() 被触发。常见有效场景包括:
- 修改响应式对象的已有属性:
this.obj.a = 123 - 通过
Vue.set或vm.$set添加新属性:this.$set(this.obj, 'b', 456) - 数组变异方法调用:
this.list.push(789)、this.list.splice(0, 1) - 使用
ref.value或reactive对象的属性赋值(Vue 3)
以下操作不会触发缓存失效:
- 对非响应式变量赋值(如普通 const/let 变量)
- 直接添加对象顶层属性(
this.obj.newKey = 'x',未用Vue.set) - 用索引直接设置数组项(
this.list[0] = 'x',不触发响应) - 修改计算属性自身(除非你写了 setter,且 setter 中显式改了依赖)
为什么首次访问不立即计算?——惰性求值的体现
computed 不会在组件创建时立刻执行 getter,即使它已被定义。它只在第一次被读取时才初始化依赖、执行计算、建立缓存。这意味着:
- 如果某个 computed 在整个生命周期中从未被访问,它的 getter 一次都不会执行
- 模板里没用到、JS 代码里没读取、watch 里没监听,它就始终处于“未激活”状态
- 这种设计避免了无意义的预计算,是性能优化的关键一环
如何验证缓存是否失效
最直接的方式是在 computed 的 getter 中加 console.log:
```jscomputed: {
fullName() {
console.log('fullName 计算中');
return this.firstName + ' ' + this.lastName;
}
}
```
你会发现:修改 firstName 后,log 不会立刻打印;只有下一次模板渲染或 JS 访问 fullName 时,log 才出现——这就是 dirty → true → 下次读取时重算 的完整链路。











