VUE - MVVM - part2 - Dep

看這篇以前,若是沒看過 step1 先移步看 實現 VUE 中 MVVM - step1 - definePropertyvue

在上一篇咱們大概實現了,Vue 中的依賴收集和觸發,但咱們僅僅是將依賴維護在一個內置數組中,這樣作雖然容易理解,但畢竟很差維護,爲了更容易的維護這些依賴,咱們來實現一個維護依賴的類。git

肯定功能

首先咱們能夠先肯定這個類下的屬性,以及一些功能:github

類下屬性:數組

  • target 函數,用於存放須要添加的依賴

實例下屬性及方法:瀏覽器

  • subs/Array 用於存放依賴
  • addSub/Function 用於添加依賴
  • removeSub/Function 用於移除依賴
  • notify/Function 用於執行依賴

實現

考慮到直接放在瀏覽器上執行,因此直接用 ES5 的類寫法。函數

let Dep = function(){

    // 實例屬性
    this.subs = []
    
    // 實例方法
    this.addSub = function(sub){
        this.subs.push(sub)
    }
    
    this.removeSub = function(sub){
        const index = this.subs.indexOf(item)
        if (index > -1) {
            this.subs.splice(index, 1)
        }
    }
    
    this.notify = function(newValue, oldVaule){
        this.subs.forEach(fnc=>fnc(newValue, oldVaule))
    }
}

// 類屬性
Dep.target = null

好了,如今咱們擁有了一個管理依賴的類(這裏將依賴簡化爲一個方法),如今咱們就能夠動手來改一下以前的代碼了。優化

let defineReactive = function(object, key, value){
    let dep = new Dep()
    Object.defineProperty(object, key, {
        configurable: true,
        enumerable: true,
        get: function(){
            if(Dep.target){
                dep.addSub(Dep.target)
            }
            return value
        },
        set: function(newValue){
            if(newValue != value){
                dep.notify(newValue, value)
            }
            value = newValue
        }
    })
}

能夠發現,以前咱們用來存放依賴的數組變成了一個依賴管理(Dep)的實例。一樣的,在取值時收集依賴,在設置值(當值發生變化)時觸發依賴。this

因爲依賴的處理由 Dep 的實例管理了,這裏僅僅調用一下相關方法便可。code

接下來試一試效果:blog

let object = {}
defineReactive(object, 'test', 'test')
Dep.target = function(newValue, oldValue){
    console.log('我被添加進去了,新的值是:' + newValue)
}
object.test
// test

Dep.target = null
object.test = 'test2'
// 我被添加進去了,新的值是:test2

Dep.target = function(newValue, oldValue){
    console.log('添加第二個函數,新的值是:' + newValue)
}
object.test
// test

Dep.target = null
object.test = 'test3'
// 我被添加進去了,新的值是:test3
// 添加第二個函數,新的值是:test3

可是上面的代碼暴露了幾個問題

  1. Dep 這個類將監聽屬性和處理依賴進行了解耦,可是卻沒有徹底解耦,在觸發依賴的時候,仍是得傳新舊值。
  2. 上面代碼中 Dep 中定義的 removeSub 在代碼中並無用到,由於 Dep 的實例是在 defineReactive 函數的做用域中,外部並不能直接調用,而刪除依賴確定是在外部的環境中,也就是說即便咱們將代碼改爲這樣,咱們仍是不能直接取刪除已經沒用的依賴。

Vue 中實現了一個 Watcher 的類來處理以上兩個問題,以後再說。

如下 ES6 語法下的 DepVue 源碼中差很少就這樣

class Dep {

    constructor() {
        this.subs = []
    }

    addSub(sub) {
        this.subs.push(sub)
    }

    removeSub(sub) {
        const index = this.subs.indexOf(item)
        if (index > -1) {
            this.subs.splice(index, 1)
        }
    }

    notify() {
        this.subs.forEach(fnc=>fnc(oldValue, newValue))
    }
}

Dep.target = null

點擊查看相關代碼

系列文章地址

  1. VUE - MVVM - part1 - defineProperty
  2. VUE - MVVM - part2 - Dep
  3. VUE - MVVM - part3 - Watcher
  4. VUE - MVVM - part4 - 優化Watcher
  5. VUE - MVVM - part5 - Observe
  6. VUE - MVVM - part6 - Array
  7. VUE - MVVM - part7 - Event
  8. VUE - MVVM - part8 - 優化Event
  9. VUE - MVVM - part9 - Vue
  10. VUE - MVVM - part10 - Computed
  11. VUE - MVVM - part11 - Extend
  12. VUE - MVVM - part12 - props
  13. VUE - MVVM - part13 - inject & 總結
相關文章
相關標籤/搜索