(1).Object.defineProperty
該方法是Object對象定義屬性的方法,能夠修改屬性默認的特性javascript
/*參數解釋: obj表示目標對象,即屬性所在的對像; key表示屬性名; 最後一個參數表示屬性的描述符對象 */ Object.defineProperty(obj, key, { configurable: false, //屬性是否能夠被刪除或修改,默認爲false enumerable: false, //屬性是否可枚舉,默認爲false writeable: true, //屬性的值可否修改,默認爲true value: 'yayaya', //包含該屬性的數據值 get: function() {}, //獲取屬性的方法 set: function() {} //設置屬性的方法 })
(2).觀察者模式(發佈-訂閱)
(3).舉例解析雙向綁定
<1>.響應式基本原理
例1:
基本思路:渲染視圖 <=監聽每一個data的數據變化 <=遍歷data中的每一項 <=獲取數據html
html中代碼: <!DOCTYPE html> <html> <head> <title>demo</title> </head> <body> <div id="demo"> </body> </html> <script type="text/javascript" src="vue2.js"></script> <script> //new 一個 Vue 對象,就會將 data 中的數據進行「 響應式」化 var v = new Vue({ el: '#demo', data: { name: '123' }, }) v._data.name = '456'; </script>
vue2.js中代碼:vue
function Vue(options) { //獲取數據 this._data = options.data; observe(this._data); } function observe(value) { //遍歷data中的每一項 //先不考慮value爲數組的複雜狀況 if (!value || typeof value !== 'object') return; Object.keys(value).forEach(function(propertyName) { defineReactive(value, propertyName, value[propertyName]) }) } function defineReactive(obj, key, val) { //監聽每一個data的數據變化 console.log('defineReactive==parameter', obj, key, val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, set: function(newVal) { console.log('newVal', newVal); if (val == newVal) return; update(); //若是新修改的值和原來的值不一樣就從新渲染頁面 }, get: function() { return val; } }) } function update() { console.log("update view===") }
輸出結果:java
小結:從data到視圖view的響應式原理主要用到的是Object.definePorperty對數據進行劫持,再更新視圖數組
<2>.依賴收集
1>爲何要有依賴收集this
例1: var globalData = { name: 'yayaya', age: '26' } var vue1 = new Vue({ data: { name: globalData.name } }) var vue2 = new Vue({ data: { name: globalData.name } })
假如咱們修改了globalData中name的值,那麼vue1和vue2實例中用到全局name的地方都須要更新,這個時候就須要依賴收集,告訴觀察者哪些實例下的數據須要更新.spa
2>.依賴收集的實現過程雙向綁定
1.訂閱者Dep:Dep的主要做用是存放Watcher觀察者對象 function Dep() { //添加觀察者watcher this.subs = []; this.addSub = function(sub) { this.subs.push(sub); console.log("sub==", sub); } //通知Watcher更新視圖 this.notify = function() { this.subs.forEach(function(s) { s.update() }); } } Dep.target = null; 2.觀察者Watcher:主要做用是監聽數據變化更新視圖 function Watcher() { Dep.target = this; //在new 一個Watcher 對象時將該對象賦值給Dep.target,在get 中會用到 this.update = function() { console.log('updata view===') } } 3.在defineReactivez和Vue中實現依賴收集 function defineReactive(obj, key, val) { //監聽data中的數據變化 var dep = new Dep();//實例化一個訂閱者 Object.defineProperty(obj, key, { enumerable: true, configurable: true, set: function(newVal) { //在set時發送通知給Watcher,從新渲染視圖 console.log("set start==="); if (val == newVal) return; dep.notify(); //若是新修改的值和原來的值不一樣就從新渲染頁面 }, get: function() { //get時添加依賴 console.log("get start==="); dep.addSub(Dep.target); //把watcher實例添加到依賴中 return val; } }) } function Vue(options) { //獲取數據 this._data = options.data; observe(this._data); new Watcher(); console.log("this._data.name", this._data.name) } function observe(value) { //遍歷data中的每一項 //先不考慮value爲數組的複雜狀況 if (!value || typeof value !== 'object') return; Object.keys(value).forEach(function(propertyName) { defineReactive(value, propertyName, value[propertyName]) }) } 4.組件中的代碼 var v = new Vue({ el: '#demo', data: { name: '123' }, }) console.log("name is changing") v._data.name = '456';
輸出結果:code
小結:
首先vue在observe中註冊並調用get,在get中,將Watcher實例經過addSub方法添加到dep的subs數組中,這完成了依賴添加的過程; 當數據變化時,調用Object.defineProperty中的set方法,判斷數據是否發生改變,若是改變了,就調用dep中的notify方法通知Watcher,Watcher知道數據變化更新數據.htm