我又來吹牛逼了,這次我們簡單說一下vue的數據雙向綁定,我們這次不背題,而是要你理解這個流程,保證讀完就懂,逢人能講,面試必過,如果沒做到,請再來看一遍,走起:
介紹雙向數據之前,我們先解釋幾個名詞:
1、什么是setter、getter ?
答:首先,別誤以為他們就是一會要說的get、set,我們先看一句定義:
對象有兩種屬性:(1)數據屬性,就是我們經常使用的屬性(2)訪問器屬性,也稱存取器屬性(存取器屬性就是一組獲取和設置值的函數)
再看一行代碼:
log打印出來的如下:
數據屬性就是a和b;
get和set就是關鍵字 它們后面各自對應一個函數,這個函數就是上面紅字部分所講的,存儲器屬性。
get對應的方法稱為getter,負責獲取值,它不帶任何參數。set對應的方法為setter,負責設置值,在它的函數體中,一切的return都是無效的。
2、什么是Object.defineProperty() ?
答:老規矩走起,我們先看一句定義:
對象是由多個名/值對組成的無序的集合。對象中每個屬性對應任意類型的值。
定義對象可以使用構造函數或字面量的形式:
除了以上添加屬性的方式,當然還可以使用Object.defineProperty定義新屬性或修改原有的屬性;
語法:
Object.defineProperty(obj, prop, descriptor)
參數:
obj:必需。目標對象;
prop:必需。需定義或修改的屬性的名字;
descriptor:必需。目標屬性所擁有的特性;
返回值:
傳入函數的對象,即第一個參數obj;
OK,定義介紹完了,我們現在說一下一會關於雙向綁定我們要用到的知識點:存取器描述;(誒?你是不是發現和上面好像有點關系)
對頭,它是這樣使用的:
現在無論是你獲取還是設置我們都可以接到通知,是不是有一點雙向數據綁定的影子了,別急下面還有;
OK,我終於叨叨完沒用的了,現在開始說正題,如何理解Vue的雙向數據綁定,哈哈,先來一個定義:
Vue是采用數據劫持結合發布/訂閱模式的方式,通過
Object.defineProperty()
來劫持各個屬性的setter
,getter
,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。
我們來看一個很粗暴的栗子,low版雙向綁定:
是不是有點明白了呢,當然這也不是全部,我們剛剛說的大概就是下面Observer的部分,對每個vue中的data中定義的屬性循環用Object.defineProperty()實現數據劫持,以便利用其中的setter和getter,然后通知訂閱者,訂閱者會觸發它的update方法,對視圖進行更新。
別急,下面也很簡單:
Dep,它就像一個依賴管理一樣,小伙伴又問啥是依賴管理倪? 上圖!
我用一個例子來解釋一下上面這張圖 下面高能預警:
在vue中v-model,v-name,{{}}等都可以對數據進行展示,也就是說假如一個屬性都通過這三個指令了,那么每當這個屬性改變的時候,相應的這個三個指令的html視圖也必須改變;
於是vue中就是每當有這樣的可能用到雙向綁定的指令,就在一個Dep中增加一個訂閱者(addSub),其訂閱者只是更新自己的指令對應的數據,也就是v-model='name'和{{name}}有兩個對應的訂閱者,各自管理自己的地方;
每當屬性的set方法觸發,就循環更新Dep中的訂閱者(notify);
OK,Dep是不是很明白了呢
集合上面的那張圖來看,就是Observer一旦有了set觸發,就會通知到Dep,那Dep接到通知之后呢?從圖上來看,下面所講的就應該是Compile了,也很簡單:
首先,先要知道它負責干什么?
compile主要做的事情是解析模板指令,將模板中的變量替換成數據
其次知道它什么時候要工作,只有兩種情況,先上圖:
1)初始化,init的時候 初始化渲染頁面視圖;
2)將每個指令對應的節點綁定更新函數,添加監聽數據的訂閱者;
Dep負責維護依賴,而訂閱者則來自於compile,一旦有數據變動,則會綁定更新函數,此時也就是產生了訂閱者,這個時候Dep內就增加了一個訂閱者,而一旦數據變動,則會收到通知,更新視圖;
好了,你是不是覺得上面這行說不通,或是讀不通,當然,因為上面的這個流程了缺少了,我們最后要說的Watcher,我把上面這句話補全,就是Watcher的工作了;
Dep負責維護依賴,而訂閱者則來自於compile,一旦有數據變動,則會通過Watcher綁定更新函數,此時Watcher也向Dep中添加了訂閱者,一旦Dep接到Observer的通知,它就會再去通知Watcher,Watcher則會調用自身的update()方法,並觸發Compile中綁定的回調,更新視圖;
最后敲黑板:
首先我們為每個vue屬性用Object.defineProperty()實現數據劫持,為每個屬性分配一個訂閱者集合的管理數組dep;
然后在編譯的時候在該屬性的數組dep中添加訂閱者,v-model會添加一個訂閱者,{{}}也會,v-bind也會,只要用到該屬性的指令理論上都會;
接着為input會添加監聽事件,修改值就等於為該屬性賦值,則會觸發該屬性的set方法,在set方法內通知訂閱者數組dep,訂閱者數組循環調用各訂閱者的update方法更新視圖。
參考干貨:
https://www.cnblogs.com/zhenfei-jiang/p/7542900.html
https://segmentfault.com/a/1190000006599500
感謝巨人的肩膀