vue computed的实现
Vue computed 的实现原理
Vue 的 computed 属性是基于响应式依赖进行缓存的计算属性,其实现主要依赖于 Vue 的响应式系统和 Watcher 机制。
核心实现步骤
初始化 computed 属性
在 Vue 实例初始化时,computed 属性会被遍历并定义为响应式属性。每个 computed 属性会创建一个对应的 Watcher 实例,并将 computed 的 getter 函数作为 Watcher 的求值函数。
function initComputed(vm, computed) {
const watchers = vm._computedWatchers = Object.create(null);
for (const key in computed) {
const getter = typeof computed[key] === 'function'
? computed[key]
: computed[key].get;
watchers[key] = new Watcher(
vm,
getter,
noop,
{ lazy: true } // 标记为 computed watcher
);
defineComputed(vm, key, computed[key]);
}
}
定义 computed 属性
通过 Object.defineProperty 将 computed 属性代理到 Vue 实例上,并重写 getter 和 setter。
function defineComputed(target, key, def) {
const shouldCache = !isServerRendering();
if (typeof def === 'function') {
def = { get: def };
}
Object.defineProperty(target, key, {
enumerable: true,
configurable: true,
get: shouldCache
? createComputedGetter(key)
: def.get,
set: def.set || noop
});
}
computed getter 的实现
当访问 computed 属性时,会触发 getter 函数。该函数会检查依赖是否变化,决定是否重新计算值。
function createComputedGetter(key) {
return function computedGetter() {
const watcher = this._computedWatchers && this._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {
watcher.evaluate(); // 重新计算值
}
if (Dep.target) {
watcher.depend(); // 收集依赖
}
return watcher.value;
}
};
}
Watcher 的更新机制
computed watcher 在初始化时会被标记为 lazy,首次不会立即求值。当依赖的响应式数据变化时,会触发 watcher 的更新,但不会立即重新计算,而是标记为 dirty,等到下次访问时再重新计算。
class Watcher {
constructor(vm, expOrFn, cb, options) {
this.lazy = !!options.lazy;
this.dirty = this.lazy;
if (typeof expOrFn === 'function') {
this.getter = expOrFn;
}
this.value = this.lazy ? undefined : this.get();
}
evaluate() {
this.value = this.get();
this.dirty = false;
}
update() {
if (this.lazy) {
this.dirty = true; // 标记为脏,下次访问时重新计算
} else {
this.run();
}
}
}
关键设计点
缓存机制
computed 属性会根据依赖是否变化来决定是否重新计算。只有当依赖变化时,才会在下一次访问时重新计算,否则直接返回缓存值。
依赖收集
在 computed getter 执行时,会触发依赖的响应式数据的 getter,从而将当前的 computed watcher 收集为依赖。当这些依赖变化时,会通知 computed watcher 更新。
惰性求值
computed 属性在首次访问时才会进行计算,并且只有在依赖变化后再次访问时才会重新计算,这种惰性求值机制提高了性能。







