initWatch
- 始化数据会执行initWatch,initWatch的核心是createWatcher
function initWatch (vm, watch) {
for (var key in watch) {
var handler = watch[key];
// handler可以是数组的形式,执行多个回调
if (Array.isArray(handler)) {
for (var i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i]);
}
} else {
createWatcher(vm, key, handler);
}
}
}
//进行watcher的格式转换,统一将回调都转换成function
function createWatcher (vm,expOrFn,handler,options) {
// 针对watch是对象的形式,此时回调回选项中的handler
if (isPlainObject(handler)) {
options = handler;
handler = handler.handler;
}
//watcher的回调是methods里的方法
if (typeof handler === 'string') {
handler = vm[handler];
}
return vm.$watch(expOrFn, handler, options)
}
$watch
Vue.prototype.$watch = function (expOrFn,cb,options) {
var vm = this;
//如果回调不是function,则进行格式转换
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {};
//标识用户定义的watcher
options.user = true;
//在watcher初始化时,将Dep.target改为自身,非计算属性watcher会进行一次求值,从而能访问到依赖的响应式数据的getter,收集到该依赖,计算完成后,Dep.target回退成上一个watcher
var watcher = new Watcher(vm, expOrFn, cb, options);
// 当watch有immediate选项时,立即执行cb方法,即不需要等待属性变化,立刻执行回调。
if (options.immediate) {
try {
cb.call(vm, watcher.value);
} catch (error) {
handleError(error, vm, ("callback for immediate watcher \"" + (watcher.expression) + "\""));
}
}
//返回取消监听,即从管理的deps数组中删掉该watcher
return function unwatchFn () {
watcher.teardown();
}
};
}
var Watcher = function Watcher() {
···
this.value = this.lazy
? undefined
: this.get();
}
Watcher.prototype.get = function get() {
···
try {
// getter回调函数,触发依赖收集
value = this.getter.call(vm, vm);
}
}
- 在watcher初始化时,将Dep.target改为自身,非计算属性watcher会进行一次求值,从而能访问到依赖的响应式数据的getter,收集到该依赖,计算完成后,Dep.target回退成上一个watcher
- 所以依赖的响应式对象改变时,能够触发到监听回调