VUE - MVVM - part4 - 優化Watcher

看這篇之前,假如沒有看過之前的文章,可拉到文章末端檢察之前的文章。

回憶

起首我們思索一下停止當前,我們都做了什麼

  1. 經由歷程 defineReactive 這個函數,完成了關於數據取值和設置的監聽
  2. 經由歷程 Dep 類,完成了依靠的治理
  3. 經由歷程 Watcher 類,籠統出了對象下某個屬性的依靠,以及屬性變更的 callBack

發現題目

對照 VueMVVM(先把視圖層的襯着籠統成一個函數),我們僅僅是完成了一些基本性的東西。另有很大的區分,比方

  1. 我們的 Watcher 僅僅是籠統了對象下的單一屬性,而平常視圖層的襯着是觸及多個屬性的,而這些屬性的變化是同一個襯着函數(也就是 Vue 中編譯模板字符串終究天生的函數)。
  2. 經由歷程第一點,我們能夠得知,對象下的某幾個屬性是具有同一個 Watcher 的,換句話說就是,多個 Dep 依靠與同一個 Watcher,那末 Watcher 中該怎樣保留這些 Dep ,由於根據我們的完成,都一個 Watcher 中僅僅堅持一個 Dep

解決題目

題目1

先讓我們想一想,我們是怎樣把依靠注入到 Dep 中的

經由歷程取值觸發 defineProperty 中的 get,然後增添依靠

換句話說就是,我只需取過對應屬性的值,那末就能夠增添依靠。
看到之前 Watcher 的完成:

this.get = function () {
    Dep.target = this
    let value = this.getter.call(object)
    Dep.target = null
    return value
}

這段代碼就完成了增添響應屬性的依靠,歸根究竟是這段起了作用

let value = this.obj[this.getter]

這裏觸發了對應屬性的 get ,那好針對第一個題目,我們只需在這裏觸發多個屬性的 get 即可,至於要觸發那些屬性,我們交由挪用者來掌握,水到渠成的這裏應該是一個函數。斟酌以後便有了以下代碼

let Watcher = function (object, getter, callback) {
    this.obj = object
    // 這裏的 getter 應該是一個函數
    this.getter = getter
    this.cb = callback
    this.dep = null
    this.value = undefined

    this.get = function () {
        Dep.target = this
        // 將取值體式格局改成函數挪用
        let value = this.getter.call(object)
        Dep.target = null
        return value
    }

    this.update = function () {
        const value = this.getter.call(object)
        const oldValue = this.value
        this.value = value
        this.cb.call(this.obj, value, oldValue)
    }

    this.addDep = function (dep) {
        this.dep = dep
    }

    this.value = this.get()
}

題目二

題目二實在很簡單,既然要保留多個 dep 我們把保留的值聲明成一個數組即可

let Watcher = function (object, getter, callback) {
    this.obj = object
    this.getter = getter
    this.cb = callback
    // 聲明成數組
    this.deps = []
    this.value = undefined

    this.get = function () {
        Dep.target = this
        let value = this.getter.call(object)
        Dep.target = null
        return value
    }

    this.update = function () {
        const value = this.getter.call(object)
        const oldValue = this.value
        this.value = value
        this.cb.call(this.obj, value, oldValue)
    }

    this.addDep = function (dep) {
        // 將 dep 推入數組中
        this.deps.push(dep)
    }

    this.value = this.get()
}

為了輕易作廢這個 Watcher ,我們在增添一個函數,用於作廢一切 DepWatcher 的依靠,所以終究 Watcher 的代碼以下:

let Watcher = function (object, getter, callback) {
    this.obj = object
    this.getter = getter
    this.cb = callback
    this.deps = []
    this.value = undefined

    this.get = function () {
        Dep.target = this
        let value = this.getter.call(object)
        Dep.target = null
        return value
    }

    this.update = function () {
        const value = this.getter.call(object)
        const oldValue = this.value
        this.value = value
        this.cb.call(this.obj, value, oldValue)
    }

    this.addDep = function (dep) {
        this.deps.push(dep)
    }

    // 新增添的作廢依靠的要領
    this.teardown = function () {
        let i = this.deps.length
        while (i--) {
            this.deps[i].removeSub(this)
        }
        this.deps = []
    }

    this.value = this.get()
}

測試

我們僅僅優化了 Watcher 的完成,其他的代碼並沒有發生變化

let object = {}
defineReactive(object, 'num1', 2)
defineReactive(object, 'num2', 4)

let watcher = new Watcher(object, function () {
    return this.num1 + this.num2
}, function (newValue, oldValue) {
    console.log(`這是一個監聽函數,${object.num1} + ${object.num2} = ${newValue}`)
})

object.num1 = 3
// 這是一個監聽函數,3 + 4 = 7
object.num2 = 10
// 這是一個監聽函數,3 + 10 = 13

let watcher2 = new Watcher(object, function () {
    return this.num1 * this.num2
}, function (newValue, oldValue) {
    console.log(`這是一個監聽函數,${object.num1} * ${object.num2} = ${newValue}`)
})

object.num1 = 4
// 這是一個監聽函數,4 + 10 = 14
// 這是一個監聽函數,4 * 10 = 40
object.num2 = 11
// 這是一個監聽函數,4 + 11 = 15
// 這是一個監聽函數,4 * 11 = 44

// 測試作廢
watcher2.teardown()

object.num1 = 5
// 這是一個監聽函數,5 + 11 = 16
object.num2 = 12
// 這是一個監聽函數,5 + 12 = 17

這就完成了關於多個屬性設置同一個監聽,當監聽函數中的依靠屬性發生變化時,自動執行了響應的函數。

關於 Vue 中的 MVVM 的完成 ,差不多也就如許了,固然這僅僅是基本的完成,而且視圖層層襯着籠統成一個函數。

不同於 Vue 中的完成,這裏少了許多種種標記和運用標記的歷程。

這些會增添明白難度,以後有用到再說,完成完全的 MVVM 還需要對數組舉行特別的處置懲罰,由於數組是不能用 Object.defineProperty 來處置懲罰索引值的,這個也以後再說。

點擊檢察相干代碼

系列文章地點

  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 & 總結
    原文作者:aco
    原文地址: https://segmentfault.com/a/1190000014365141
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞