MVVM原理(Object.defineProperty和訂閱者模式)

想着去了解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實例去作的。
相關文章
相關標籤/搜索