// 爲data的的全部屬性添加getter 和 setter function defineReactive( obj,key,val,customSetter,shallow ) { // var dep = new Dep(); /*....省略部分....*/ var childOb = !shallow && observe(val); //爲對象添加備份依賴dep,val在此採用記憶模式進行存儲 Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { var value = getter ? getter.call(obj) : val; if (Dep.target) { dep.depend(); // if (childOb) { childOb.dep.depend(); //依賴dep 添加watcher 用於set ,array改變等使用 if (Array.isArray(value)) { dependArray(value); } } } return value }, set: function reactiveSetter(newVal) { var value = getter ? getter.call(obj) : val; /* eslint-disable no-self-compare */ if (newVal === value || (newVal !== newVal && value !== value)) { return } /* eslint-enable no-self-compare */ if ("development" !== 'production' && customSetter) { customSetter(); } if (setter) { setter.call(obj, newVal); } else { val = newVal; } childOb = !shallow && observe(newVal); dep.notify();//有改變觸發watcher進行更新 } }); }
Vue.prototype.$watch = function ( expOrFn, cb, options ) { var vm = this; if (isPlainObject(cb)) { return createWatcher(vm, expOrFn, cb, options) } options = options || {}; options.user = true; //爲須要觀察的 expOrFn 添加watcher ,expOrFn的值有改變時執行cb, //在watcher的實例化的過程當中會對expOrFn進行解析,併爲expOrFn涉及到的data數據下的def添加該watcher var watcher = new Watcher(vm, expOrFn, cb, options); //immediate==true 當即執行watch handler if (options.immediate) { cb.call(vm, watcher.value); } //取消觀察函數 return function unwatchFn() { watcher.teardown(); } };
var Watcher = function Watcher( vm, expOrFn, cb, options, isRenderWatcher ) { this.vm = vm; if (isRenderWatcher) { vm._watcher = this; } vm._watchers.push(this); // options if (options) { this.deep = !!options.deep; //是否觀察對象內部值的變化 this.user = !!options.user; this.lazy = !!options.lazy; this.sync = !!options.sync; } else { this.deep = this.user = this.lazy = this.sync = false; } this.cb = cb; // 觀察屬性改變時執行的函數 this.id = ++uid$1; // uid for batching this.active = true; this.dirty = this.lazy; // for lazy watchers this.deps = []; this.newDeps = []; this.depIds = new _Set(); this.newDepIds = new _Set(); this.expression = expOrFn.toString(); // parse expression for getter if (typeof expOrFn === 'function') { this.getter = expOrFn; } else { // 將須要觀察的數據:string | Function | Object | Array等進行解析 如:a.b.c, 並返回訪問該表達式的函數 this.getter = parsePath(expOrFn); if (!this.getter) { this.getter = function () { }; "development" !== 'production' && warn( "Failed watching path: \"" + expOrFn + "\" " + 'Watcher only accepts simple dot-delimited paths. ' + 'For full control, use a function instead.', vm ); } } // this.get()將訪問須要觀察的數據 this.value = this.lazy ? undefined : this.get(); }; /** * Evaluate the getter, and re-collect dependencies. */ Watcher.prototype.get = function get() { //this爲$watch方法中實例化的watcher pushTarget(this);講this賦給Dep.target並緩存以前的watcher var value; var vm = this.vm; try { //訪問須要觀察的數據,在獲取數據的getter中執行dep.depend();將$watch方法中實例化的watcher添加到對應數據下的dep中 value = this.getter.call(vm, vm); } catch (e) { if (this.user) { handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\"")); } else { throw e } } finally { // "touch" every property so they are all tracked as // dependencies for deep watching if (this.deep) {// 若是是進行深度觀察,在此依次訪問對象下的屬性,以便將該watcher實例添加到對應屬性的dep中 traverse(value); } popTarget(); //將以前的watcher賦給Dep.target this.cleanupDeps(); } return value };
觀察的對象改變時將執行該方法
Watcher.prototype.run = function run() { /*....省略部分....*/ var value = this.get(); //從新獲取info的值 var oldValue = this.value; //保存老的值 this.value = value; this.cb.call(this.vm, value, oldValue); //執行watch的回調 /*....省略部分....*/ };
以上代碼在watcher實例化的時候執行 this.getter = parsePath(expOrFn); 返回一個訪問該屬性的函數,參數爲被訪問的對象 如vm.$watch("info",function(new, old){console.log("watch success")});, this.getter =function(obj){return obj.info};,在執行watcher的get方法中,將執行value = this.getter.call(vm, vm);,觸發屬性的get方法,添加該watcher至info屬性對應的def對象中,若是須要深度監聽,將執行traverse(value),依次訪問info(假設info只對象)對象下的屬性,若是info的屬性還有是對象的屬性,將進行遞歸訪問,以達到info以及info下全部的屬性的def對象都會添加該watcher實例。javascript
當咱們執行vm.info="change"時,將出發info的set方法,執行dep.notify();出發info所依賴的watcher執行watcher的run方法,即實現監聽vue
舉例java