你們好,我是蘇日儷格,在不少次面試的時候, 面試官都會多多少少問到vue的雙向數據綁定的原理是什麼? 這個問題就很尷尬了, 我當初來如今的這家公司的時候初試和複試都遇到了這個問題, 不只如此, 以前面試的幾家公司也都問了這個讓我值得深思又避免不了尷尬的問題, 在這兩天完成了本身的任務後, 靜了下心來回想一下這個問題.html
在網上查找許多資料, 多是IT界的大佬們講的太專業太深奧了, 也多是我真的真的是一個名副其實的理工科生, 對文字理解能力差吧, 可我仍是沒懂, 後來讓我這個歷來不愛讀書的孩子在書中找到了這個黃金屋, 偶然發現了有關綁定數據屬性的問題, 下面我把個人理解跟你們分享一下,本文純屬我的理解,有哪裏不對的地方請在評論區指出,你們一塊兒學習共同進步。vue
所謂雙向數據綁定, 無非就是數據層和視圖層中的數據同步, 在寫入數據時視圖層實時的跟着更新, 以前在網上看到大佬們是這麼描述的:git
實現mvvm的雙向綁定,是採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。就必需要實現如下幾點:
一、實現一個數據監聽器Observer,可以對數據對象的全部屬性進行監聽,若有變更可拿到最新值並通知訂閱者
二、實現一個指令解析器Compile,對每一個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數
三、實現一個Watcher,做爲鏈接Observer和Compile的橋樑,可以訂閱並收到每一個屬性變更的通知,執行指令綁定的相應回調函數,從而更新視圖
四、mvvm入口函數,整合以上三者github
一共分四步, 每一步都有大堆解釋和一大堆的代碼, 然而我真的只是一個名副其實的理工科生, 看到了文中的發佈者-訂閱者模式, 因而乎我去網上各類百度, 我的理解就是getter函數裏面執行的任務就是watcher訂閱者, 而setter函數執行的任務就是發佈者; 相信不少人看過了這個也是隻知其一;不知其二, 下面我來解釋一波:面試
ECMAScript中有兩種屬性: 數據屬性和訪問器屬性, 數據屬性通常用於存儲數據數值, 訪問器屬性對應的是set/get操做, 不能直接存儲數據值, 每種屬性下面又都含有四個特性.下面介紹一下:mvvm
1.[[Configurable]]: 表示可否經過delete將屬性刪除,可否把屬性修改成訪問器屬性, 默認爲false。當把屬性Configurable設置爲false後,該屬性不能經過delete刪除,而且也沒法再將該屬性的Configurable設置回true
2.[[Enumerable]]: 表示屬性能否被枚舉(便是否能夠經過for in循環返回),默認false
3.[[Writable]]: 表示屬性是否可寫(便是否能夠修改屬性的值),默認false
4.[[Value]]: 該屬性的數據值, 默認是undefined函數
1.[[Configurable]]: 表示可否經過delete將屬性刪除,可否把屬性修改成數據屬性, 默認爲false。當把屬性Configurable設置爲false後,該屬性不能經過delete刪除,而且也沒法再將該屬性的Configurable設置回true
2.[[Enumerable]]: 表示屬性能否被枚舉(便是否能夠經過for in循環返回),默認false
3.[[Get]]: 讀取屬性時調用的函數, 默認爲undefined
4.[[Set]]: 寫入屬性時調用的函數, 默認是undefined學習
在修改屬性的特性或者定義訪問器屬性的時候, 須要藉助ECMAScript 5中的一個方法: Object.defineProperty(), 這個方法接收三個參數: 屬性所在對象, 屬性的名字, 描述符對象; 爲對象定義多個屬性的話, 就用函數的複數寫法:Object.defineProperties();spa
那麼經過這個ES5的方法就能夠直接很簡單粗暴的說明雙向綁定的原理:雙向綁定
<input type="text" id="inp" /> <div id="box"></div> <script> let obj = {}; let oInp = document.getElementById('inp'); let oBox = document.getElementById('box'); Object.defineProperty(obj, 'name', { configurable: true, enumerable: true, get: function() { console.log(111) return val; }, set: function(newVal) { oInp.value = newVal; oBox.innerHTML = newVal; } }); oInp.addEventListener('input', function(e) { obj.name = e.target.value; }); obj.name = '蘇日儷格';
那麼實現數據雙向綁定的核心就是利用爲每個屬性都建立了訂閱者的實例對象, 以便觀察, getter函數裏面返回一個value值,在setter函數中寫入修改後的值並調用update方法更新視圖的數據值, Configurable和Enumerable這兩個特性描述符默認是true, 所以不用寫
function defineReactive (obj, key, val) { var dep = new Dep(); //這是一個構造函數 其原型是爲屬性添加訂閱者 Object.defineProperty(obj, key, { get: function() { if(Dep.target) { dep.addSub(Dep.target); //添加訂閱者到Dep實例對象 } return val; // 返回監聽到的value值 }, set: function (newVal) { if(newVal === val) return; val = newVal; // 寫入新的value值 dep.notify(); // 做爲發佈者發出通知 而後dep會迭代調用各自的update方法來更新視圖 } }); } function observe(obj, vm) { Object.keys(obj).forEach(function(key) { defineReactive(vm, key, obj[key]); }); }
若是想要仔細研究的能夠參考一下他的博客或者http://www.cnblogs.com/canfoo/p/6891868.html
但願你們閱讀完本文能夠有所收穫,由於能力有限,掌握的知識也是不夠全面,歡迎你們提出來一塊兒分享!謝謝O(∩_∩)O~
歡迎訪問個人GitHub,喜歡的能夠star,項目隨意fork,支持轉載但要下標註,同時恭候:我的博客