vue3源码学习6-计算属性computed
packages/reactivity/src/computed.ts
export function computed<T>(
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
debugOptions?: DebuggerOptions,
isSSR = false
) {
// getter函数
let getter: ComputedGetter<T>
// setter函数
let setter: ComputedSetter<T>
// 标准化参数
const onlyGetter = isFunction(getterOrOptions)
// 如果只有getter函数,不能修改计算属性的值
if (onlyGetter) {
getter = getterOrOptions
setter = __DEV__
? () => {
console.warn('Write operation failed: computed value is readonly')
}
: NOOP
} else {
getter = getterOrOptions.get
setter = getterOrOptions.set
}
const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)
return cRef as any
}
接下来看ComputedRefImpl的实现:
export class ComputedRefImpl<T> {
public dep?: Dep = undefined
private _value!: T
public readonly effect: ReactiveEffect<T>
public readonly __v_isRef = true
public readonly [ReactiveFlags.IS_READONLY]: boolean = false
// 数据是否是脏的
public _dirty = true
public _cacheable: boolean
constructor(
getter: ComputedGetter<T>,
private readonly _setter: ComputedSetter<T>,
isReadonly: boolean,
isSSR: boolean
) {
// 特性1:只有当访问计算属性的时候,才会真正运行computed getter函数计算
this.effect = new ReactiveEffect(getter, () => {
if (!this._dirty) {
// 派发通知,通知运行访问该计算属性的activeEffect
this._dirty = true
triggerRefValue(this)
}
})
this.effect.computed = this
this.effect.active = this._cacheable = !isSSR
this[ReactiveFlags.IS_READONLY] = isReadonly
}
get value() {
// 计算属性的getter
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
const self = toRaw(this)
// 依赖收集,收集运行访问该属性的activeeEffect
trackRefValue(self)
// 特性2:缓存,会自动缓存上次的计算结果_value,而且只有dirty为true时,才会重新计算,否则直接返回_value
// 典型的空间换时间的优化思想
if (self._dirty || !self._cacheable) {
// 只有数据为脏的时候才进行计算
self._dirty = false
self._value = self.effect.run()!
}
return self._value
}
set value(newValue: T) {
// 计算属性的setter
this._setter(newValue)
}
}