1. 程式人生 > >面試問題:Vuejs如何實現雙向繫結

面試問題:Vuejs如何實現雙向繫結

最近出去面試,栽在這個問題上,提到vuejs,面試官一般會讓你說vuejs的特點,一般就要回答virtual dom tree, dom tree diff, 以及資料雙向繫結,然後面試官會追問你,vuejs是如何實現資料雙向繫結的,前面的問題算基礎的話,能答出這個就更上一個臺階,說明你的思考能力不停留在表層,遺憾的是我只能大概說出Object.defineProperty。
我回來搜了一下,發現其實vuejs的官網對這個原理是有詳盡的闡釋的,如果失敗了只能怪自己準備不足。這篇文章我就整理一下分享給大家,如果有錯誤還請指出。

vuejs官網對這個問題的解釋是 對響應式原理的解釋,這裡:https://cn.vuejs.org/v2/guide...

問題就是vuejs如何追蹤物件的屬性變化,答是利用es5的Object.defineProperty,參考:https://developer.mozilla.org...

Object.defineProperty是一個無法被shim的屬性,就是說它無法被降級使用,這也是vuejs不支援ie8以下的根本原因。

Object.defineProperty用來設定一個物件的某一個屬性,這都不是最關鍵的,關鍵是在設定屬性的同時,可以設定setter/getter,setter/getter設定兩個函式,在這個屬性被呼叫或者設定的時候自動執行,所以在setter的函式裡,只要寫了更新dom的方法,就可以在這個屬性變化的時候執行,實現了屬性變化的追蹤。

實際上,vuejs的實現更加複雜,遵照這張流程圖:

vuejs裡每一個元件對應了一個watcher,Object.defineProperty是紫色的圓圈,當元件裡某一個屬性被get的時候,getter函式會通知Watcher,“說我這有一個屬性被渲染了,你記一下”,然後當這個屬性的setter被觸發(也就是該屬性資料被修改的時候),也會通知Watcher,說“我這有這樣一個東西被改了,你看看在不在你的名單裡。”Watcher此時去檢查被改的屬性在不在自己記錄的名單裡,如果在,就通知元件渲染程式,讓它再去更新虛擬dom樹。

需要注意的幾個點:

1.getter/setter對使用者是不可見的,是在vue內部實現的。
2.js裡無法監聽物件屬性的增加或者刪除,所以vue只能在開始data裡新增響應式屬性,所以當元件建立完畢,再給這個元件塞一個屬性,這個屬性是無法響應到dom的。
3.vue會在元件初始化的過程中進行getter/setter轉換,所以也無法動態插入新屬性,插入了也是非響應資料,但可以通過Vue.set(object, key, value)方法將屬性加入到後臺可響應的物件中。
4.官網還介紹了更新佇列,上文說的Watcher中的更新會被推入到一個更新佇列中,那麼就是說資料更新後不會馬上反映到dom上。
5.但是我們可以通過Vue.nextTick(callback)方法,將這次資料更新馬上反映到dom上,這個方法的callback是dom更新完成的回撥。

來源:https://segmentfault.com/a/1190000016884795