成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Vue原理】依賴收集 - 源碼版之引用數(shù)據(jù)類型

vvpvvp / 1887人閱讀

摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理依賴收集源碼版之引用數(shù)據(jù)類型上

寫文章不容易,點個贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧
研究基于 Vue版本 【2.5.17】

如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧

【Vue原理】依賴收集 - 源碼版之引用數(shù)據(jù)類型

上一篇,我們已經(jīng)分析過了 基礎(chǔ)數(shù)據(jù)類型的 依賴收集

【Vue原理】依賴收集 - 源碼版之基本數(shù)據(jù)類型

這一篇內(nèi)容是針對 引用數(shù)據(jù)類型的數(shù)據(jù)的 依賴收集分析,因為引用類型數(shù)據(jù)要復雜些,必須分開寫

文章很長,高能預(yù)警,做好準備耐下心好,肯定還是有點收獲的

但是兩個類型的數(shù)據(jù)的處理,又有很多重復的地方,所以打算只寫一些差異性的地方就好了,否則顯得廢話很多

兩個步驟,都有不同的地方

1、數(shù)據(jù)初始化

2、依賴收集

數(shù)據(jù)初始化流程

如果數(shù)據(jù)類型是引用類型,需要對數(shù)據(jù)進行額外的處理。

處理又分了 對象 和 數(shù)組 兩種,會分開來講

1對象

1、遍歷對象的每個屬性,同樣設(shè)置響應(yīng)式,假設(shè)屬性都是基本類型,處理流程跟上一篇一樣

2、每個數(shù)據(jù)對象會增加一個 ob 屬性

比如設(shè)置一個 child 的數(shù)據(jù)對象

下圖,你可以看到 child 對象處理之后添加了一個 ob 屬性

ob_ 屬性有什么用啊?

你可以觀察到,__ob__ 有一個 dep 屬性,這個 dep 是不是有點屬性,是的,在上一篇基礎(chǔ)數(shù)據(jù)類型中講過

那么這個 ob 屬性有什么用?。?/p>

你可以觀察到,__ob__ 有一個 dep 屬性,這個 dep 是不是有點屬性,是的,在上一篇基礎(chǔ)數(shù)據(jù)類型中講過

dep 正是存儲依賴的地方

比如 頁面引用了 數(shù)據(jù)child,watch 引用了數(shù)據(jù)child,那么child 就會把這個兩個保存在 dep.subs 中

dep.subs = [ 頁面-watcher,watch-watcher ]

但是,在上一篇基礎(chǔ)類型種, dep 是作為閉包存在的啊,并不是保存在什么【__ob__.dep】 中啊

沒錯,這就是 引用類型 和 基礎(chǔ)類型的區(qū)別了

基礎(chǔ)數(shù)據(jù)類型,只使用 【閉包dep】 來存儲依賴

引用數(shù)據(jù)類型,使用 【閉包dep】 和 【 __ob__.dep】 兩種來存儲依賴

什么?你說閉包dep 在哪里?好吧,在 defineReactive 的源碼中,你去看看這個方法的源碼,下面有

那么,為什么,引用類型需要 使用__ob__.dep 存儲依賴呢?

首先,明確一點,存儲依賴,是為了數(shù)據(jù)變化時通知依賴,所以 __ob__.dep 也是為了變化后的通知

閉包 dep 只存在 defineReactive 中,其他地方無法使用到,所以需要保存另外一個在其他地方使用

在其他什么地方會使用呢?

在Vue掛載原型上的方法 set 和 del 中,源碼如下

function set(target, key, val) {    

    var ob = (target).__ob__;    

    // 通知依賴更新
    ob.dep.notify();
}
Vue.prototype.$set = set;
function del(target, key) {    

    var ob = (target).__ob__;    

    delete target[key];    

    if (!ob)  return

    // 通知依賴更新
    ob.dep.notify();

}
Vue.prototype.$delete = del;

這兩個方法,大家應(yīng)該都用過,為了給對象動態(tài) 添加屬性和 刪除屬性

但是如果直接添加屬性或者刪除屬性,Vue 是監(jiān)聽不到的,比如下面這樣

child.xxxx=1

delete child.xxxx

所以必須要通過 Vue 包裝過的方法 set 和 del 來操作

在 set 和 del 執(zhí)行完,是需要通知依賴更新的,但是我怎么通知?

此時,【__ob__.dep】 就發(fā)揮作用了!就因為依賴多收集了一份在 __ob__.dep 中

使用就是上面一句話,通知更新

ob.dep.notify();

2、數(shù)組

1、需要遍歷數(shù)組,可能數(shù)組是對象數(shù)組,如下面

[{name:1},{name:888}]

遍歷時,如果遇到子項是對象的,會跟上面解析對象一樣操作

2、給數(shù)組保存一個 ob 屬性

比如設(shè)置一個 arr 數(shù)組

看到 arr數(shù)組 加多了一個 ob 屬性

其實這個 ob 屬性 和 上一段講對象 的作用是差不多的,這里也只是說 __ob__.dep

數(shù)組中的 __ob__.dep 存儲的也是依賴,給誰用呢?

給 Vue 封裝的數(shù)組方法使用,要知道要想數(shù)組變化也被監(jiān)聽到,是必須使用Vue封裝的數(shù)組方法的,否則無法實時更新

這里舉重寫方法之一 push,其他的還有 splice 等,Vue 官方文檔已經(jīng)有過說明

var original = Array.prototype.push;

Array.prototype.push = function() {    

    var args = [],

    len = arguments.length;    

    // 復制 傳給 push 等方法的參數(shù)
    while (len--) args[len] = arguments[len];

    // 執(zhí)行 原方法
    var result = original.apply(this, args);    

    var ob = this.__ob__;    

    // notify change
    ob.dep.notify();    

    return resul
}

看到在執(zhí)行完 數(shù)組方法之后,同樣需要通知依賴更新,也就是通知 __ob__.dep 中收集的依賴去更新

現(xiàn)在,我們知道了,響應(yīng)式數(shù)據(jù)對 引用類型做了什么額外的處理,主要是加了一個 ob 屬性

我們已經(jīng)知道了 ob 有什么用,現(xiàn)在看看源碼是怎么添加 ob

// 初始化Vue組件的數(shù)據(jù)

function initData(vm) {    

    var data = vm.$options.data;

    data = vm._data = 

        typeof data === "function" ? 

        data.call(vm, vm) : data || {};

    ....遍歷 data 數(shù)據(jù)對象的key ,重名檢測,合規(guī)檢測
    observe(data, true);

}

function observe(value) {    

    if (Array.isArray(value) || typeof value == "object") {
        ob = new Observer(value);
    }    
    return ob
}
function Observer(value) {   

    // 給對象生成依賴保存器
    this.dep = new Dep();   

    // 給 每一個對象 添加一個  __ob__ 屬性,值為 Observer 實例
    value.__ob__ = this

    if (Array.isArray(value)) { 

        // 遍歷數(shù)組,每一項都需要通過 observe 處理,如果是對象就添加 __ob__
        for (var i = 0, l =value.length; i < l; i++) {
            observe(value[i]);
        }

    } else {        

        var keys = Object.keys(value);     

        // 給對象的每一個屬性設(shè)置響應(yīng)式
        for (var i = 0; i < keys.length; i++) {
            defineReactive(value, keys[i]);
        }
    }
};

源碼的流程跟上一篇差不多,只是處理引用數(shù)據(jù)類型會增加多幾行源碼的額外處理

我們之前只說了一種對象數(shù)據(jù)類型,比如下面這樣

如果會嵌套多層對象呢?比如這樣,會怎么處理

沒錯,Vue 會遞歸處理,當遍歷屬性,使用 defineReactive 處理時,遞歸調(diào)用 observe 處理(源碼標紅加粗)

如果值是對象,那么同樣給 值加多一個 ob

如果不是,那么正常往下走,設(shè)置響應(yīng)式

源碼如下

function defineReactive(obj, key, value) {  

    // dep 用于中收集所有 依賴我的 東西
    var dep = new Dep();    
    var val  = obj[key] 

    // 返回的 childOb 是一個 Observer 實例
    // 如果值是一個對象,需要遞歸遍歷對象
    var childOb = observe(val);    

    Object.defineProperty(obj, key, {
        get() {...依賴收集跟初始化無關(guān),下面會講},
        set() { .... }
    });
}

畫一個流程圖,僅供參考

哈哈哈,上面寫得好長啊,是有點,但是沒辦法,想說詳細點啊,好吧,還有一段,但是比較短一些哈哈哈,反正看完的人,我jio 得很厲害了,答應(yīng)我,如果你仔細看完了,評論一下好嗎,讓我知道有人仔細看了

依賴收集流程

收集流程,就是重點關(guān)注 Object.defineProperty 設(shè)置的 get 方法了

跟 基礎(chǔ)類型數(shù)據(jù) 對比,引用類型的 收集方法也只是多了幾行處理,差異在兩行代碼

childOb.dep.depend,被我 簡單化為 childOb.dep.addSub(Dep.target)
dependArray(value)
可以先看下源碼,如下

function defineReactive(obj, key, value) {    

    var dep = new Dep();    
    var val  = obj[key]    
    var childOb = observe(val);    

    Object.defineProperty(obj, key, {
        get() {            
            var value = val            
            if (Dep.target) {

                // 收集依賴進 dep.subs
                dep.addSub(Dep.target);

                // 如果值是一個對象,Observer 實例的 dep 也收集一遍依賴
                if (childOb) {
                    childOb.dep.addSub(Dep.target)          
                    if (Array.isArray(value)) {
                        dependArray(value);
                    }
                }
            }            
            return value
        }
    });
}

上面的源碼,混雜了 對象和 數(shù)組的處理,我們分開說

1、對象

在數(shù)據(jù)初始化的流程中,我們已經(jīng)知道值是對象的話,會存儲多一份依賴在 __ob__.dep 中

就只有一句話

childOb.dep.depend();

數(shù)組還有另外一個處理,就是

dependArray(value);

看下源碼,如下

function dependArray(value) {    

    for (var i = 0, l = value.length; i < l; i++) {        

        var e = value[i];        

        // 只有子項是對象的時候,收集依賴進 dep.subs
        e && e.__ob__ && e.__ob__.dep.addSub(Dep.target);   
     

        // 如果子項還是 數(shù)組,那就繼續(xù)遞歸遍歷
        if (Array.isArray(e)) {
            dependArray(e);
        }
    }
}

顯然,是為了防止數(shù)組里面有對象,從而需要給 數(shù)組子項對象也保存一份

你肯定會問,為什么子項對象也要保存一份依賴?

1、頁面依賴了數(shù)組,數(shù)組子項變化了,是不是頁面也需要更新?但是子項內(nèi)部變化怎么通知頁面更新?所以需要給子項對象也保存一份依賴?

2、數(shù)組子項數(shù)組變化,就是對象增刪屬性,必須用到Vue封裝方法 set 和 del,set 和 del 會通知依賴更新,所以子項對象也要保存

看個栗子

頁面模板

看到數(shù)組的數(shù)據(jù),就存在兩個 ob

總結(jié)

到這里,就可以很清楚,引用類型和 基礎(chǔ)類型的處理差異了

1、引用類型會多添加一個 __ob__屬性,其中包含 dep,用于存儲 收集到的依賴

2、對象使用 __ob__.dep,作用在 Vue 自定義的方法 set 和 del 中

3、數(shù)組使用 __ob__.dep,作用在 Vue 重寫的數(shù)組方法 push 等中

終于寫完了,真的好長,但是我覺得值得了

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/109952.html

相關(guān)文章

  • Vue原理依賴收集 - 源碼版之基本數(shù)據(jù)類型

    摘要:當東西發(fā)售時,就會打你的電話通知你,讓你來領(lǐng)取完成更新。其中涉及的幾個步驟,按上面的例子來轉(zhuǎn)化一下你買東西,就是你要使用數(shù)據(jù)你把電話給老板,電話就是你的,用于通知老板記下電話在電話本,就是把保存在中。剩下的步驟屬于依賴更新 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于 Vue版本 【...

    VincentFF 評論0 收藏0
  • Vue原理依賴更新 - 源碼

    摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關(guān)注公眾號也可以吧原理依賴更新源碼版如果對依賴收集完 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于...

    moven_j 評論0 收藏0
  • Vue原理】Props - 源碼

    寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧 【Vue原理】Props - 源碼版 今天記錄 Props 源碼流程,哎,這東西,就算是研究過了,也真是會隨著時間慢慢忘記的。 幸好我做...

    light 評論0 收藏0
  • Vue原理】NextTick - 源碼版 之 服務(wù)Vue

    寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧 【Vue原理】NextTick - 源碼版 之 服務(wù)Vue 初次看的兄弟可以先看 【Vue原理】NextTick - 白話版 簡單了解下...

    Acceml 評論0 收藏0
  • Vue原理】VModel - 源碼版之input詳解

    摘要:因為失去焦點之后被強制更新了一波嗯,這就是的作用,把頁面上的顯示值也過濾一遍 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關(guān)注公眾號也可以吧 【Vue原理】VModel - 源碼版之input詳...

    leanxi 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<