vue computed 实现原理
Vue Computed 实现原理
Vue 的 computed 属性是基于响应式依赖的缓存机制,其核心实现依赖于 Vue 的响应式系统和依赖收集机制。
依赖收集与缓存机制
computed 属性在初始化时会创建一个 Watcher 实例,并将 computed 的 getter 函数作为回调传入。当首次访问 computed 属性时,getter 函数会被执行,并在执行过程中触发依赖属性的 get 拦截器,从而将当前 Watcher 订阅到这些依赖属性的订阅列表中。

// 伪代码示例
function initComputed(vm, computed) {
const watchers = {};
for (const key in computed) {
const getter = computed[key];
watchers[key] = new Watcher(vm, getter, { lazy: true });
defineComputed(vm, key, watchers[key]);
}
}
惰性求值与缓存
computed 属性默认是惰性求值的,只有在被访问时才会计算值。如果依赖的响应式数据未发生变化,computed 会直接返回缓存的值,避免重复计算。

// Watcher 类中的相关逻辑
class Watcher {
constructor(vm, expOrFn, options) {
this.lazy = !!options.lazy;
this.dirty = this.lazy; // 初始时为 true,表示需要重新计算
this.getter = expOrFn;
this.value = this.lazy ? undefined : this.get();
}
evaluate() {
this.value = this.get();
this.dirty = false;
}
get() {
pushTarget(this); // 将当前 Watcher 设置为 Dep.target
const value = this.getter.call(this.vm);
popTarget(); // 恢复之前的 Watcher
return value;
}
}
依赖更新触发重新计算
当 computed 依赖的响应式数据发生变化时,依赖属性的 set 拦截器会通知所有订阅的 Watcher 执行更新。computed 的 Watcher 会将 dirty 标记为 true,表示需要重新计算,但不会立即执行计算,而是等到下次访问时再重新求值。
// Watcher 更新逻辑
update() {
if (this.lazy) {
this.dirty = true; // 标记为脏数据,下次访问时重新计算
} else {
queueWatcher(this); // 非 lazy 的 Watcher 直接加入队列更新
}
}
与模板的绑定
在模板中使用 computed 属性时,Vue 会在渲染过程中访问该属性,触发 getter 并收集依赖。如果依赖变化,会通知渲染 Watcher 重新渲染组件,从而间接触发 computed 的重新计算。
// 定义 computed 属性的 getter
function createComputedGetter(key) {
return function computedGetter() {
const watcher = this._computedWatchers[key];
if (watcher.dirty) {
watcher.evaluate(); // 重新计算
}
if (Dep.target) {
watcher.depend(); // 收集上层 Watcher 的依赖
}
return watcher.value;
};
}
总结
computed通过Watcher实现惰性求值和缓存。- 依赖收集发生在首次访问时,后续访问直接返回缓存值(除非依赖变化)。
- 依赖变化时标记为
dirty,下次访问时重新计算。 - 与模板绑定时,会自动触发依赖收集和更新。






