读本文之前最好对Vue的双向绑定有一定了解
1.普通组件的watch是怎么实现的?
在created生命周期钩子回调函数之前,会执行watch的初始化,在initState方法里面执行initWatch方法,
function initWatch (vm: Component, watch: Object) {
for (const key in watch) {
const handler = watch[key];
if (Array.isArray(handler)) { //监听一个属性时可以执行多个方法
for (let i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i])
}
} else {
createWatcher(vm, key, handler)
}
}
}
function createWatcher (
vm: Component,
expOrFn: string | Function,
handler: any,
options?: Object
) {
if (isPlainObject(handler)) {
options = handler
handler = handler.handler
}
if (typeof handler === 'string') {
handler = vm[handler]
}
return vm.$watch(expOrFn, handler, options)
}
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Object
): Function {
const vm: Component = this
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options);
}
options = options || {}
options.user = true
const watcher = new Watcher(vm, expOrFn, cb, options) //创建watcher
if (options.immediate) { //是否立即执行回调函数
try {
cb.call(vm, watcher.value)
} catch (error) {
handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`)
}
}
return function unwatchFn () {
watcher.teardown()
}
}
2.普通组件的computed实现方式
computed属性也是在created钩子回调前初始化的,同样是在initState里面调用initComputed实现,
function initComputed (vm: Component, computed: Object) {
const watchers = vm._computedWatchers = Object.create(null); // 给当前的vm挂载_computedWatchers属性,
// computed properties are just getters during SSR
const isSSR = isServerRendering()
for (const key in computed) {
const userDef = computed[key] //普通来说是一个方法
if (!isSSR) {
// 给每一个computed创建一个computed watcher 注意{ lazy: true }
// 然后挂载到vm._computedWatchers对象上
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions
)
}
if (!(key in vm)) {
defineComputed(vm, key, userDef)
}
}
}
export function defineComputed (
target: any,
key: string,
userDef: Object | Function
) {
const shouldCache = !isServerRendering()
if (typeof userDef === 'function') {
sharedPropertyDefinition.get = shouldCache
? createComputedGetter(key)
: createGetterInvoker(userDef)
sharedPropertyDefinition.set = noop //属性描述符
} else {
sharedPropertyDefinition.get = userDef.get
? shouldCache && userDef.cache !== false
? createComputedGetter(key)
: createGetterInvoker(userDef.get)
: noop
sharedPropertyDefinition.set = userDef.set || noop
}
Object.defineProperty(target, key, sharedPropertyDefinition)
}
//调用Getter为返回值
function createComputedGetter (key) {
return function computedGetter () {
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
// 给computed的属性添加订阅watchers
if (watcher.dirty) {
watcher.evaluate()
}
// 把渲染watcher 添加到属性的订阅里面去,这很关键
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
}
从上得出,computed其实也是基于watcher实现的,computed是有缓存的(根据dirty判断),而watcher没有,