Vue 進階 (二)

Vue 的響應式系統原理

Vue 最獨特的特性之一,是其非侵入性的響應式系統。數據模型僅僅是普通的 JavaScript 對象。而當你修改它們時,視圖會進行更新。

當你把javascript對象傳給vue實例的data屬性的時候,Vue 將遍歷此對象全部的屬性,經過 Object.defineProperty 來給每一個屬性都添加 gettersetter.javascript

而每一個組件實例又都有一個watcher對象,它會將組件渲染過程當中的屬性渲染爲【依賴】,當數據發生變化的時候,會觸發setter,會通知 watcher 從新計算,從而導致它關聯的組件得以更新。vue

1、Object.defineProperty

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
  • Writable 屬性
var o = {}; // 建立一個新對象

Object.defineProperty(o, "a", { value : 37,
                                writable : false });

console.log(o.a); // 打印 37
o.a = 25; // 沒有錯誤拋出(在嚴格模式下會拋出,即便以前已經有相同的值)
console.log(o.a); // 打印 37, 賦值不起做用。
  • Enumerable 特性
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 特性

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

相關文章
相關標籤/搜索