摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關注公眾號也可以吧原理依賴收集源碼版之引用數據類型上
寫文章不容易,點個贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧
研究基于 Vue版本 【2.5.17】
如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧
【Vue原理】依賴收集 - 源碼版之引用數據類型
上一篇,我們已經分析過了 基礎數據類型的 依賴收集
【Vue原理】依賴收集 - 源碼版之基本數據類型
這一篇內容是針對 引用數據類型的數據的 依賴收集分析,因為引用類型數據要復雜些,必須分開寫
文章很長,高能預警,做好準備耐下心好,肯定還是有點收獲的
但是兩個類型的數據的處理,又有很多重復的地方,所以打算只寫一些差異性的地方就好了,否則顯得廢話很多
兩個步驟,都有不同的地方
1、數據初始化
2、依賴收集
數據初始化流程如果數據類型是引用類型,需要對數據進行額外的處理。
處理又分了 對象 和 數組 兩種,會分開來講
1對象
1、遍歷對象的每個屬性,同樣設置響應式,假設屬性都是基本類型,處理流程跟上一篇一樣
2、每個數據對象會增加一個 ob 屬性
比如設置一個 child 的數據對象
下圖,你可以看到 child 對象處理之后添加了一個 ob 屬性
ob_ 屬性有什么用啊?
你可以觀察到,__ob__ 有一個 dep 屬性,這個 dep 是不是有點屬性,是的,在上一篇基礎數據類型中講過
那么這個 ob 屬性有什么用啊?
你可以觀察到,__ob__ 有一個 dep 屬性,這個 dep 是不是有點屬性,是的,在上一篇基礎數據類型中講過
dep 正是存儲依賴的地方
比如 頁面引用了 數據child,watch 引用了數據child,那么child 就會把這個兩個保存在 dep.subs 中
dep.subs = [ 頁面-watcher,watch-watcher ]
但是,在上一篇基礎類型種, dep 是作為閉包存在的啊,并不是保存在什么【__ob__.dep】 中啊
沒錯,這就是 引用類型 和 基礎類型的區別了
基礎數據類型,只使用 【閉包dep】 來存儲依賴
引用數據類型,使用 【閉包dep】 和 【 __ob__.dep】 兩種來存儲依賴
什么?你說閉包dep 在哪里?好吧,在 defineReactive 的源碼中,你去看看這個方法的源碼,下面有
那么,為什么,引用類型需要 使用__ob__.dep 存儲依賴呢?
首先,明確一點,存儲依賴,是為了數據變化時通知依賴,所以 __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;
這兩個方法,大家應該都用過,為了給對象動態 添加屬性和 刪除屬性
但是如果直接添加屬性或者刪除屬性,Vue 是監聽不到的,比如下面這樣
child.xxxx=1 delete child.xxxx
所以必須要通過 Vue 包裝過的方法 set 和 del 來操作
在 set 和 del 執行完,是需要通知依賴更新的,但是我怎么通知?
此時,【__ob__.dep】 就發揮作用了!就因為依賴多收集了一份在 __ob__.dep 中
使用就是上面一句話,通知更新
ob.dep.notify();
2、數組
1、需要遍歷數組,可能數組是對象數組,如下面
[{name:1},{name:888}]
遍歷時,如果遇到子項是對象的,會跟上面解析對象一樣操作
2、給數組保存一個 ob 屬性
比如設置一個 arr 數組
看到 arr數組 加多了一個 ob 屬性
其實這個 ob 屬性 和 上一段講對象 的作用是差不多的,這里也只是說 __ob__.dep
數組中的 __ob__.dep 存儲的也是依賴,給誰用呢?
給 Vue 封裝的數組方法使用,要知道要想數組變化也被監聽到,是必須使用Vue封裝的數組方法的,否則無法實時更新
這里舉重寫方法之一 push,其他的還有 splice 等,Vue 官方文檔已經有過說明
var original = Array.prototype.push; Array.prototype.push = function() { var args = [], len = arguments.length; // 復制 傳給 push 等方法的參數 while (len--) args[len] = arguments[len]; // 執行 原方法 var result = original.apply(this, args); var ob = this.__ob__; // notify change ob.dep.notify(); return resul }
看到在執行完 數組方法之后,同樣需要通知依賴更新,也就是通知 __ob__.dep 中收集的依賴去更新
現在,我們知道了,響應式數據對 引用類型做了什么額外的處理,主要是加了一個 ob 屬性
我們已經知道了 ob 有什么用,現在看看源碼是怎么添加 ob 的
// 初始化Vue組件的數據 function initData(vm) { var data = vm.$options.data; data = vm._data = typeof data === "function" ? data.call(vm, vm) : data || {}; ....遍歷 data 數據對象的key ,重名檢測,合規檢測 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)) { // 遍歷數組,每一項都需要通過 observe 處理,如果是對象就添加 __ob__ for (var i = 0, l =value.length; i < l; i++) { observe(value[i]); } } else { var keys = Object.keys(value); // 給對象的每一個屬性設置響應式 for (var i = 0; i < keys.length; i++) { defineReactive(value, keys[i]); } } };
源碼的流程跟上一篇差不多,只是處理引用數據類型會增加多幾行源碼的額外處理
我們之前只說了一種對象數據類型,比如下面這樣
如果會嵌套多層對象呢?比如這樣,會怎么處理
沒錯,Vue 會遞歸處理,當遍歷屬性,使用 defineReactive 處理時,遞歸調用 observe 處理(源碼標紅加粗)
如果值是對象,那么同樣給 值加多一個 ob
如果不是,那么正常往下走,設置響應式
源碼如下
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() {...依賴收集跟初始化無關,下面會講}, set() { .... } }); }
畫一個流程圖,僅供參考
哈哈哈,上面寫得好長啊,是有點,但是沒辦法,想說詳細點啊,好吧,還有一段,但是比較短一些哈哈哈,反正看完的人,我jio 得很厲害了,答應我,如果你仔細看完了,評論一下好嗎,讓我知道有人仔細看了
依賴收集流程收集流程,就是重點關注 Object.defineProperty 設置的 get 方法了
跟 基礎類型數據 對比,引用類型的 收集方法也只是多了幾行處理,差異在兩行代碼
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 } }); }
上面的源碼,混雜了 對象和 數組的處理,我們分開說
1、對象
在數據初始化的流程中,我們已經知道值是對象的話,會存儲多一份依賴在 __ob__.dep 中
就只有一句話
childOb.dep.depend();
數組還有另外一個處理,就是
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); // 如果子項還是 數組,那就繼續遞歸遍歷 if (Array.isArray(e)) { dependArray(e); } } }
顯然,是為了防止數組里面有對象,從而需要給 數組子項對象也保存一份
你肯定會問,為什么子項對象也要保存一份依賴?
1、頁面依賴了數組,數組子項變化了,是不是頁面也需要更新?但是子項內部變化怎么通知頁面更新?所以需要給子項對象也保存一份依賴?
2、數組子項數組變化,就是對象增刪屬性,必須用到Vue封裝方法 set 和 del,set 和 del 會通知依賴更新,所以子項對象也要保存
看個栗子
頁面模板
看到數組的數據,就存在兩個 ob
總結到這里,就可以很清楚,引用類型和 基礎類型的處理差異了
1、引用類型會多添加一個 __ob__屬性,其中包含 dep,用于存儲 收集到的依賴
2、對象使用 __ob__.dep,作用在 Vue 自定義的方法 set 和 del 中
3、數組使用 __ob__.dep,作用在 Vue 重寫的數組方法 push 等中
終于寫完了,真的好長,但是我覺得值得了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/109952.html
摘要:當東西發售時,就會打你的電話通知你,讓你來領取完成更新。其中涉及的幾個步驟,按上面的例子來轉化一下你買東西,就是你要使用數據你把電話給老板,電話就是你的,用于通知老板記下電話在電話本,就是把保存在中。剩下的步驟屬于依賴更新 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【...
摘要:寫文章不容易,點個贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于版本如果你覺得排版難看,請點擊下面鏈接或者拉到下面關注公眾號也可以吧原理依賴更新源碼版如果對依賴收集完 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于...
寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧 【Vue原理】Props - 源碼版 今天記錄 Props 源碼流程,哎,這東西,就算是研究過了,也真是會隨著時間慢慢忘記的。 幸好我做...
寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧 【Vue原理】NextTick - 源碼版 之 服務Vue 初次看的兄弟可以先看 【Vue原理】NextTick - 白話版 簡單了解下...
摘要:因為失去焦點之后被強制更新了一波嗯,這就是的作用,把頁面上的顯示值也過濾一遍 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請點擊 下面鏈接 或者 拉到 下面關注公眾號也可以吧 【Vue原理】VModel - 源碼版之input詳...
閱讀 922·2023-04-25 18:51
閱讀 1880·2021-09-09 11:39
閱讀 3287·2019-08-30 15:53
閱讀 2104·2019-08-30 13:03
閱讀 1316·2019-08-29 16:17
閱讀 591·2019-08-29 11:33
閱讀 1891·2019-08-26 14:00
閱讀 2129·2019-08-26 13:41