computed 的核心是依赖追踪与缓存复用——仅当所依赖的响应式数据变化时才重新求值,否则返回缓存结果;它通过 getter 拦截收集依赖,要求函数为纯函数,且不支持非响应式变量或异步回调中的响应式读取。

Vue.js 的 computed 不是简单地“每次取值都执行函数”,它的核心价值在于依赖追踪 + 缓存复用——只有当它所依赖的响应式数据真正发生变化时,才会重新求值;否则直接返回上一次计算结果。这是 Vue 响应式系统最精巧的性能设计之一。
依赖收集:谁变了,computed 才重算?
computed 在首次求值时,会主动“读取”其函数体中访问的所有响应式属性(如 data、props、其他 computed)。Vue 通过 getter 拦截 记录下这些访问路径,形成一张“依赖关系图”。后续只要这些被记录的属性没有触发 setter,computed 就不会重新执行。
- 例如:
fullName依赖firstName和lastName,改了age完全不影响它 - 如果 computed 内部调用了非响应式变量、Math.random()、Date.now() 或 this.$refs,这些不会被追踪,可能导致缓存失效或逻辑错误
- 异步操作(如 setTimeout、API 调用)中的响应式读取,若发生在回调里,不会被初始依赖收集捕获
缓存生效条件:不是所有函数都能被缓存
computed 缓存的前提是:函数必须是纯函数——相同输入(依赖项)始终返回相同输出,且不产生副作用。Vue 无法判断逻辑是否纯净,只按依赖变化做浅层判定。
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
- 依赖项发生 值变更(Object.defineProperty 或 Proxy 触发的 setter)才触发更新;对象内部属性增删、数组索引赋值等,需确保是响应式操作
- 使用 Vue.set / this.$set 或 ref.value = ...(Composition API)才能保证新增属性被追踪
- 避免在 computed 中修改响应式数据(如
this.count++),这既是副作用,也破坏缓存语义
与 methods 对比:为什么不能全用 methods 替代?
methods 每次渲染都执行,无缓存;computed 在模板中多次使用也只计算一次,且支持监听依赖变化自动更新 DOM。
立即学习“前端免费学习笔记(深入)”;
- 模板中写
{{ getFullName() }}(methods)→ 每次 re-render 都调用,可能重复解析字符串、遍历数组 - 写
{{ fullName }}(computed)→ 首次计算后缓存,firstName或lastName不变就不重跑 - computed 还可配合 watch 监听其变化,methods 则需手动维护状态对比
调试与破除缓存:什么时候该干预?
绝大多数场景下,你不需要也不应该手动清空 computed 缓存。但若遇到“数据明明变了,computed 却没更新”,大概率是依赖未被正确追踪:
- 检查是否对响应式对象进行了整体替换(如
this.obj = {...this.obj, newKey: val}),应改用 Vue.set 或使用 reactive + proxy(Vue 3 默认支持深层响应) - 在 Composition API 中,确保用 ref() 或 reactive() 包裹数据,且读取时保持响应式链路(如
foo.value不要意外解构丢失响应性) - 必要时可用 watch 显式监听依赖项变化,绕过 computed 缓存逻辑(适合含副作用或需精确控制时机的场景)


















