computed初始化
在实例化Vue对象得时候,我们通过computed来定义计算属性:
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
})
在实例化时,初始化计算属性initComputed(源码路径/src/core/instance/state.js)
for (const key in computed) {
const userDef = computed[key]
const getter = typeof userDef === 'function' ? userDef : userDef.get
....
//定义Watcher
vm._computedWatchers[key] = new Watcher({
vm,
getter || noop,
noop,
{ lazy: true } //调用时才计算属性的值
})
//
defineComputed(vm, key, userDef)
}
在defineComputed重新定义属性
Object.defineProperty(vm, key, {
get : function(){
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
if (watcher.dirty) { //this.dirty = this.lazy
watcher.evaluate() //调用get设置watcher.value的值
}
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
})
总结初始化流程如下:
- 为每个计算属性初始化一个Watcher对象,保存在实例得_computedWatchers变量中
- 重新定义计算属性得get属性,从Watcher中获取返回属性的值。
Watcher
evaluate () {
this.value = this.get()
this.dirty = false
}
get () {
pushTarget(this)
let value
const vm = this.vm
try {
value = this.getter.call(vm, vm) //getter为key对应的函数,执行话术获取值
} catch (e) {
if (this.user) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
} else {
throw e
}
} finally {
if (this.deep) {
traverse(value)
}
popTarget()
this.cleanupDeps()
}
return value
}