Vue 源码分析之 initComputed: 揭秘计算属性的实现细节
2023-10-13 20:59:30
导语
在 Vue.js 中,计算属性是一种特殊的属性,它可以从其他属性计算出其值。当这些被计算的属性的依赖项发生改变时,计算属性的值也会随之更新。这使得在 Vue.js 中构建动态和响应式的用户界面变得更加简单。
Vue.js 中的计算属性是通过 initComputed 方法实现的。该方法在组件实例化时被调用,用于初始化计算属性并将其与依赖项关联起来。在本文中,我们将深入分析 initComputed 方法的源码,以了解它是如何工作的。
分析 initComputed 方法
initComputed 方法位于 Vue.js 源码中的 src/core/instance/state.js 文件中。该方法首先创建一个空对象 vm._computedWatchers 来存储计算属性。然后,它遍历组件定义中的所有计算属性,并为每个属性创建一个 Watcher 实例。
export function initComputed (vm: Component) {
const watchers = vm._computedWatchers = Object.create(null)
// computed properties are just getters during SSR
const isSSR = isServerRendering()
for (const key in vm.$options.computed) {
const userDef = vm.$options.computed[key]
const getter = typeof userDef === 'function' ? userDef : userDef.get
if (getter === noop) {
warn(
`Getter of computed property "${key}" is a no-op.` +
` This will cause infinite re-renders during SSR.` +
` Add a no-op return function or an ` +
`explicit function binding in the getter.`
)
}
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions
)
if (!(key in vm)) {
defineComputed(vm, key, userDef)
} else if (isSSR) {
// suppress computed property update in SSR
startMeasure(vm, `computed ${key}`)
watchers[key].evaluate()
endMeasure(vm, `computed ${key}`)
}
}
}
1. 创建计算属性的 Watcher 实例
对于每个计算属性,initComputed 方法都会创建一个 Watcher 实例。Watcher 实例用于监听计算属性的依赖项的变化,并在这些依赖项发生改变时重新计算属性的值。
在创建 Watcher 实例时,initComputed 方法会将计算属性的 getter 函数作为 Watcher 实例的回调函数。这意味着当计算属性的依赖项发生改变时,Watcher 实例会调用计算属性的 getter 函数来重新计算属性的值。
2. 将计算属性代理到 vm 实例上
在创建了计算属性的 Watcher 实例之后,initComputed 方法会将计算属性代理到 vm 实例上。这意味着当访问计算属性时,Vue.js 会自动调用计算属性的 getter 函数来获取属性的值。
if (!(key in vm)) {
defineComputed(vm, key, userDef)
}
3. 在 SSR 期间抑制计算属性的更新
在服务器端渲染 (SSR) 期间,Vue.js 会抑制计算属性的更新。这是因为在 SSR 期间,计算属性的值是静态的,不需要重新计算。
else if (isSSR) {
// suppress computed property update in SSR
startMeasure(vm, `computed ${key}`)
watchers[key].evaluate()
endMeasure(vm, `computed ${key}`)
}
总结
在本文中,我们分析了 Vue.js 中 initComputed 方法的源码,并了解了它是如何用于初始化计算属性的。我们看到 initComputed 方法首先创建一个空对象来存储计算属性,然后遍历组件定义中的所有计算属性,并为每个属性创建一个 Watcher 实例。最后,initComputed 方法将计算属性代理到 vm 实例上,使得当访问计算属性时,Vue.js 会自动调用计算属性的 getter 函数来获取属性的值。通过对 initComputed 方法的源码分析,我们对 Vue.js 的响应式系统和计算属性的实现细节有了更深入的理解。