vue2.x響應(yīng)式原理

vue3.0發(fā)布了,回顧一波2.x原理

vue 2.x 響應(yīng)式原理

image

主要做了這么幾件事:數(shù)據(jù)劫持、收集依賴、派發(fā)更新

  1. 數(shù)據(jù)劫持:new Vue的時(shí)候遍歷data對(duì)象,用Object.defineProperty給所有屬性加上了getter和setter
  2. 依賴的收集:render的過(guò)程,會(huì)觸發(fā)數(shù)據(jù)的getter,在getter的時(shí)候把當(dāng)前的watcher對(duì)象收集起來(lái)
  3. 派發(fā)更新:setter的時(shí)候,遍歷這個(gè)數(shù)據(jù)的依賴對(duì)象(watcher對(duì)象),進(jìn)行更新

數(shù)據(jù)劫持

通過(guò)Object.defineProperty劫持對(duì)象屬性,讓數(shù)據(jù)變?yōu)槭强捎^察的


class Vue {
    constructor(options) {
        observer(options.data);
    }
    observer(value) {
        if (!value || (typeof value !== 'object')) {
            return;
        }
        // 遍歷data對(duì)象 逐個(gè)加上getter setter
        Object.keys(value).forEach(key => defineReactive(value, key, value[key]));
    }
    defineReactive(obj, key, val) {
        const dep = new Dep(); // Dep是依賴收集類
        Object.defineProperty(obj, key, {
            enumerable: true, // 屬性可枚舉
            configurable: true  //屬性可被修改或刪除
            get() {
                dep.addSub(Dep.target); // 依賴采集
                return val;
            },
            set(newVal) {
                if (newVal === val) return;
                dep.notify(newVal); // 派發(fā)更新
            }
        })
    }
}

可以看到主要就是這個(gè)defineReactive函數(shù),他利用Object.defineProperty實(shí)現(xiàn)了數(shù)據(jù)劫持

依賴收集&派發(fā)更新

那么vue是怎么知道當(dāng)數(shù)據(jù)改變的時(shí)候都要去通知誰(shuí)呢?它用了一個(gè)訂閱者Dep,它用來(lái)存放我們的觀察者對(duì)象,當(dāng)數(shù)據(jù)發(fā)生改變,就通知觀察者,觀察者通過(guò)調(diào)用自己的update方法完成更新。

<!--訂閱者Dep類-->

class Dep {
    constructor () {
        this.newDeps = [] // 用來(lái)存放我們的依賴對(duì)象(也即觀察者)
    }
    addDep (watcher) {
        this.newDeps.push(watcher) // 向隊(duì)列里新加一下watcher對(duì)象
    }
    update () {
        this.newDeps.forEach((sub) => {
            sub.update(); // 遍歷watcher進(jìn)行更新
        })
    }
}

<!--觀察者Watcher類-->
class Watcher {
    constructor  () {
        Dep.target = this  // new Watcher的時(shí)候把觀察者存放到Dep.target里面
    }
    update () {
        console.log("視圖更新啦~"); // 更新視圖
        <!--queueWatcher(this) 異步更新策略 后面再寫一篇介紹 -->
    }
}

new一個(gè)Watcher對(duì)象,此時(shí)它會(huì)指向Dep.target,在render過(guò)程觸發(fā)getter,把Dep.target添加到依賴隊(duì)列。這樣便完成了依賴的收集。數(shù)據(jù)改變,通知依賴進(jìn)行update操作。

image

以上代碼是2.x版本響應(yīng)式原理的代碼模擬,在vue中這幾個(gè)類都是單獨(dú)的文件,源碼地址。

另外vue對(duì)數(shù)組做了特殊處理,數(shù)組的響應(yīng)式原理我補(bǔ)充在了另一篇文章里vue響應(yīng)式原理-數(shù)組篇

last but not least, 老鐵請(qǐng)留步,點(diǎn)個(gè)贊再走~??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容