【重學前端框架】Vue中的視圖更新原理(一)

前言

Vue2.0中的響應式處理(數據改變視圖改變)的核心是Object.definedProperty。vue

data中的變量纔是響應式變量,但對於對象類型的變量,給其添加新的屬性或刪除屬性時,視圖不能響應到值的變化;對於數組類型的變量,經過數組下標修改屬性值,視圖不是不能響應到值的變化,經過push、pop、splice等方法修改數組的值,視圖可以響應值的變化。爲何是這樣的規則?先從Object.definedProperty的使用規則開始提及。segmentfault

Object.definedProperty的使用規則

一、給{}類型對象的屬性從新定義規則數組

function defineReactive(obj, key, val) {
        Object.defineProperty(obj, key, {
            enumerable: true, // 可枚舉
            configurable: true, // 可寫
            get: function() {
                console.log('get');
                return val;
            },
            set: function(newVal) {
                // 設置時,能夠添加相應的操做
                console.log('set:', val);
                val += newVal;
            }
        });
    }
    let obj = {name: '成龍大哥', say: ':其實我以前是拒絕拍這個遊戲廣告的,'};
    Object.keys(obj).forEach(k => {
        defineReactive(obj, k, obj[k]);
    });
    obj.say = '後來我試玩了一下,哇,好熱血,蠻好玩的'; //會觸發set
    obj.age = 20 //不會觸發set
    console.log(obj.name + obj.say, obj);

對於新增的對象屬性不會觸發set方法。函數

二、給數組[]類型對象的屬性從新定義規則性能

function defineReactive(obj, key, val) {
        Object.defineProperty(obj, key, {
            enumerable: true, // 可枚舉
            configurable: true, // 可寫
            get: function() {
                console.log('get');
                return val;
            },
            set: function(newVal) {
                // 設置時,能夠添加相應的操做
                console.log('set:', val);
                val += newVal;
            }
        });
    }
   
    let arr = [1,2,3,4,5];
    arr.forEach((v, i) => { 
        defineReactive(arr, i, v);
    });
    arr[0] = 'oh nanana'; // 觸發set
    arr.push(6) // 不會觸發set
    console.log(arr)
    
    let arr2 = [{name: '1'},{name: '2'}, {name: '3'}];
    arr2.forEach((v, i) => { 
        defineReactive(arr2, i, v);
    });
    arr2.forEach((v, i) => { 
        v.status= true // 不會觸發set
    });
    arr2.forEach((v, i) => { 
        v.name = true // 不會觸發set
    });
    
    arr2[0] = {name: 2} // 會觸發set
    arr2.splice(1,1,{name: 111}) // 會觸發set
    arr2.push({name: 'tt'}) // 不會觸發set
    arr2.length = 2 // 不會觸發set

初始化時會將data中的值經過defineProperty設置爲響應式,當給變量賦值時就會觸發變量對應的set方法,從而調用視圖更新的函數。spa

這裏要說的是Object.definedProperty是能夠經過數組下標修改值以後觸發對應的set方法的,經過push、pop等方法修改數組的值以後是不會觸發set方法。code

可是Vue中考慮到性能問題,對於數組類型的數據改變本身定義了一套觸發響應的規則,經過數組下標修改數組的值是不會觸發視圖更新的,可是經過push、pop、shift、unshift等方法修改數組的值是能夠觸發視圖更新的。對象

Vue官方說法不會觸發視圖更新的狀況:blog

一、對於數組對象遊戲

二、對於{}對象

Vue對數組作了哪些處理呢?

默認的Object.definedProperty中,對於操做數組的方法,默認只有利用數組中的splice修改數組值時能夠觸發set(splice(1, 1, value), 至關於經過數組下標修改屬性值)。

但由於Vue作了處理,如下變異方法修改數組的值均可以觸發視圖的更新。

vue究竟對數組如何作的處理呢?見下一節

參考資料:

記一次思否問答的問題思考:Vue爲何不能檢測數組變更

相關文章
相關標籤/搜索