vue computed 实现
Vue computed 实现原理
Vue 的 computed 属性是基于响应式依赖进行缓存的计算属性。其核心实现依赖于 Vue 的响应式系统和 Watcher 机制。
基本实现原理
computed 属性初始化时会创建一个 lazy Watcher。这个 Watcher 不会立即求值,只有在真正被访问时才会计算。计算过程中会收集依赖的响应式数据,当这些依赖发生变化时,标记 computed 属性为脏状态(dirty),下次访问时重新计算。
关键实现步骤
-
初始化阶段
在组件初始化时,Vue 会遍历 computed 对象,为每个 computed 属性创建一个 Watcher 实例。这个 Watcher 的 lazy 选项设置为 true,表示延迟计算。 -
依赖收集
当首次访问 computed 属性时,触发 getter 函数执行计算。计算过程中访问的响应式属性会被记录为依赖。
-
缓存机制
计算完成后,结果会被缓存。只要依赖没有变化,后续访问直接返回缓存值,避免重复计算。 -
依赖更新
当依赖的响应式数据发生变化时,标记 computed 为 dirty 状态。下次访问时会重新计算并更新缓存。
示例代码实现
class Dep {
constructor() {
this.subscribers = new Set()
}
depend() {
if (activeEffect) {
this.subscribers.add(activeEffect)
}
}
notify() {
this.subscribers.forEach(effect => effect())
}
}
let activeEffect = null
function watchEffect(effect) {
activeEffect = effect
effect()
activeEffect = null
}
class ComputedRef {
constructor(getter) {
this._dirty = true
this._value = undefined
this._getter = getter
this.effect = () => {
if (!this._dirty) {
this._dirty = true
}
}
watchEffect(this.effect)
}
get value() {
if (this._dirty) {
this._value = this._getter()
this._dirty = false
}
return this._value
}
}
function computed(getter) {
return new ComputedRef(getter)
}
使用示例
const count = { value: 0 }
const double = computed(() => count.value * 2)
console.log(double.value) // 0
count.value++
console.log(double.value) // 2
性能优化点
-
惰性求值
computed 属性只有在被访问时才会计算,避免不必要的计算开销。 -
缓存机制
依赖未变化时直接返回缓存值,减少重复计算。 -
智能依赖追踪
自动追踪计算过程中用到的响应式数据,精确控制更新时机。
与 methods 的区别
computed 属性是基于它们的响应式依赖进行缓存的,只有在相关依赖发生改变时才会重新求值。而 methods 调用总会执行函数,没有缓存机制。






