想着去了解vue的mvvm數據驅動是怎麼實現的,百度中看了這篇文章,demo很好。其餘文章只是講到defineProperty的set,get。
完全理解Vue中的Watcher、Observer、Depvue
我把文章的代碼demo簡化成本身的代碼而且作了註釋
class Observer { constructor(targetObject) { //console.log('targetObject',targetObject); //def(targetObject, '__ob__', this);//在 targetObject 上 添加 Observer 實例, setter時 通知該實例 Object.defineProperty(targetObject, '__ob__', { value: this, //enumerable: !!enumerable, writable: true, configurable: true }); //給對象的每一個屬性設置get set方法 Object.keys(targetObject).forEach(key => { //console.log('targetObject',targetObject,'key',key,'targetObject[key]',targetObject[key]); defineReactive(targetObject, key, targetObject[key])//給對象(包括對象內的對象)定義GET SET方法 }); //給每一個Observer都添加dep實例 this.dep = new Dep() //手動執行訂閱 //this.dep.depend() } } function observe(data) { if (Object.prototype.toString.call(data) !== '[object Object]') { return } new Observer(data) } function defineReactive(obj, key, val) { //再去判斷對象屬性的值是否是對象,是的話給該對象也新增__ob__屬性 observe(val) //上面的oberve()執行完畢以後對象內全部的對象都有__ob__屬性 //去給對象(包括對象內的對象)設置get set方法 Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { console.log('get'); const ob = this.__ob__ ob.dep.depend(); return val }, set: function reactiveSetter(newVal) { console.log('set'); if (newVal === val) return val = newVal observe(newVal)//新值若是是對象也要給其設置__ob__(值爲Observer實例) const ob = this.__ob__ ob.dep.notify(newVal); }, }) } class Dep { constructor() { this.subs = [] } addSub(sub) { this.subs.push(sub) } depend() { this.subs.push(Dep.target) } notify(val) { for (let i = 0; i < this.subs.length; i++) { this.subs[i].fn(val) } } } Dep.target = null class Watcher { constructor(vm, exp, fn) { //console.log('vm',vm,'exp',exp,'fn',fn) this.vm = vm this.exp = exp this.fn = fn Dep.target = this//將本身掛載到 Dep.target,調用 Dep.depend時會讀取該變量 this.vm[exp]//取值 觸發get方法 依賴 } } //實驗代碼 const obj = { a: 1, b: { c: 2 } } new Observer(obj) console.log('給obj內全部對象設置__ob__以及SET,GET方法',obj) //在obj這個對象去監聽a這個屬性的變化(執行訂閱) new Watcher(obj, 'a', (val) => { console.log('obj.a設置了新值了',val); }) obj.a='222';
全部Vue中的MVVM是用Object.defineProperty和訂閱者模式實現的。 設置GET動做是去添加依賴(訂閱),SET方法是根據依賴(訂閱)菜單去發佈更新的值,而真正去作動做的(好比更新到DOM中去)是__ob__的值(即observer)中dep中每一個watcher實例去作的。