最近出去面試,栽在這個問題上,提到vuejs,面試官通常會讓你說vuejs的特色,通常就要回答virtual dom tree, dom tree diff, 以及數據雙向綁定,而後面試官會追問你,vuejs是如何實現數據雙向綁定的,前面的問題算基礎的話,能答出這個就更上一個臺階,說明你的思考能力不停留在表層,遺憾的是我只能大概說出Object.defineProperty。
我回來搜了一下,發現其實vuejs的官網對這個原理是有詳盡的闡釋的,若是失敗了只能怪本身準備不足。這篇文章我就整理一下分享給你們,若是有錯誤還請指出。html
vuejs官網對這個問題的解釋是 對響應式原理的解釋,這裏:https://cn.vuejs.org/v2/guide...vue
問題就是vuejs如何追蹤對象的屬性變化,答是利用es5的Object.defineProperty,參考:https://developer.mozilla.org...react
Object.defineProperty是一個沒法被shim的屬性,就是說它沒法被降級使用,這也是vuejs不支持ie8如下的根本緣由。面試
Object.defineProperty用來設置一個對象的某一個屬性,這都不是最關鍵的,關鍵是在設置屬性的同時,能夠設置setter/getter,setter/getter設置兩個函數,在這個屬性被調用或者設置的時候自動執行,因此在setter的函數裏,只要寫了更新dom的方法,就能夠在這個屬性變化的時候執行,實現了屬性變化的追蹤。dom
實際上,vuejs的實現更加複雜,遵守這張流程圖:
ide
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更新完成的回調。ui