Vue 最獨特的特性之一,是其非侵入性的響應式系統。數據模型僅僅是普通的
JavaScript
對象。而當你修改它們時,視圖會進行更新。
當你把javascript對象傳給vue實例的data屬性的時候,Vue 將遍歷此對象全部的屬性,經過 Object.defineProperty
來給每一個屬性都添加 getter
和 setter
.javascript
而每一個組件實例又都有一個watcher
對象,它會將組件渲染過程當中的屬性渲染爲【依賴】,當數據發生變化的時候,會觸發setter
,會通知 watcher
從新計算,從而導致它關聯的組件得以更新。vue
Object.defineProperty()
方法直接在一個對象上定義一個新屬性,或者修改一個已經存在的屬性, 並返回這個對象。java
Object.defineProperty(obj, prop, descriptor)
參數函數
obj
須要定義屬性的對象。prop
需被定義或修改的屬性名。descriptor
需被定義或修改的屬性的描述符。Object.defineProperty(obj, "key", { enumerable: false, // 不可枚舉 configurable: false, // 不可更改 writable: false, // 不可被賦值運算符改變 value: "static" }) // 建立屬性 var o = {}; Object.defineProperty(o, 'a', { enumerable: true, configurable: true, writable: true, value: 17 }); // 對象o擁有了屬性a,值爲17 var bValue = 38; Object.defineProperty(o, 'b', { get: function() { return bValue; }, set: function(newValue) { bValue = newValue; }, enumerable: true, configurable: true }); o.b; // 38
var o = {}; // 建立一個新對象 Object.defineProperty(o, "a", { value : 37, writable : false }); console.log(o.a); // 打印 37 o.a = 25; // 沒有錯誤拋出(在嚴格模式下會拋出,即便以前已經有相同的值) console.log(o.a); // 打印 37, 賦值不起做用。
var o = {}; Object.defineProperty(o, "a", { value : 1, enumerable:true }); Object.defineProperty(o, "b", { value : 2, enumerable:false }); Object.defineProperty(o, "c", { value : 3 }); // enumerable defaults to false o.d = 4; // 若是使用直接賦值的方式建立對象的屬性,則這個屬性的enumerable爲true for (var i in o) { console.log(i); } // 打印 'a' 和 'd' (in undefined order) Object.keys(o); // ["a", "d"] o.propertyIsEnumerable('a'); // true o.propertyIsEnumerable('b'); // false o.propertyIsEnumerable('c'); // false
configurable
特性表示對象的屬性是否能夠被刪除,以及除 writable 特性外的其餘特性是否能夠被修改。this
Object.defineProperty(person,'a',{ configurable:false,//爲false的時候不容許修改默認屬性了 }) =============================== # 改成false以後再試試修改其餘屬性 Object.defineProperty(person,'a',{ configurable:true, enumerable:true, writable:true, value:1 }) //woa,控制檯直接報錯了!連想把false值改回true都不行!也就是說,這個改動是一次性了! //也就是說,你可使用Object.defineProperty()方法無限修改同一個屬性,可是當把configurable改成false以後就有限制了
1 、首先定義一個cb函數,這個函數用來模擬試圖更新。code
// function cb (val) { /* 渲染視圖 */ console.log("視圖更新啦~"); }
二、 定義一個defineReactive ,這個方法經過 Object.defineProperty
來實現對對象的「響應式」化,入參是一個 obj(須要綁定的對象)
、key(obj的某一個屬性)
,val(具體的值)
。server
function defineReactive(obj, key, val){ Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function(){ return val; }, set:function(newVal) { if (newVal === val) return; cb(newVal); } }) } // 當一個對象,賦值給Vue實力的data選項的時候,就會觸發該操做,對數據進行響應化處理
三、 固然這是不夠的,咱們須要在上面再封裝一層 observer 。這個函數傳入一個 value(須要「響應式」化的對象),經過遍歷全部屬性的方式對該對象的每個屬性都經過 defineReactive 處理
。對象
function observer(val) { if(!val || typeof val != 'object') { return ; } Object.keys(val).forEach((key)=> { defineReactive(val,key, val[key]); }) }
四、 在 Vue 的構造函數中,對 options 的 data 進行處理ip
class Vue { /* Vue構造類 */ constructor(options) { this._data = options.data; observer(this._data); } }
五、 這樣咱們只要 new 一個 Vue 對象,就會將 data 中的數據進行「響應式」化。若是咱們對 data 的屬性進行下面的操做,就會觸發 cb 方法更新視圖。get