vue原始碼解析之資料代理

MasonEast發表於2019-03-25

Vue大家都不陌生了,用的人也很多,但大家對裡面的資料代理,模板解析渲染,v-開頭的事件指令和一般指令,資料強制繫結,雙向資料繫結如何實現的是否也產生過好奇,接下來幾篇,我們來一起探討一下這些東西,首先從比較簡單的資料代理開始。 資料代理就是通過一個物件代理來對另一個物件中的屬性實現讀和寫的操作。好處就是很大程度上方便了我們運算元據。 在vue中,我們是不是經常通過this.msg就拿到了data中的msg屬性值。 其實this就是指向new Vue建構函式建立出來的vm例項,通過資料代理來實現對data物件中所有屬性的讀寫操作,我們先寫個vue的例項物件,就像下面這樣:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="test">
        {{msg}}
    </div>

    <script>
        const vm = new Vue({
            el: '#test',
            data:{
                msg: '天氣不錯'
            }
        })
        console.log(vm)
    </script>
</body>
</html>
複製程式碼

當我們用vm.msg也可以拿到data物件中的msg屬性。 列印出來的vm是這樣的:

在這裡插入圖片描述
vm拿到了data物件中的屬性和值,並且

vm._data.msg = '今天是陰天啊'
複製程式碼

通過vm我們也能完成對data物件裡面資料的更改。 那麼問題來了,vm例項是如何完成對data物件裡的屬性實現讀寫的? 在這裡,我們就要先了解一下ES5中的Object.defineProperty()方法,看下MDN的解釋:

在這裡插入圖片描述
我們需要給這個方法傳遞三個引數,第一個是要在哪個物件上面定義屬性,第二個是要定義或修改的屬性的名稱,第三個可以理解為是一個配置物件,在裡面可以配置下列屬性:
在這裡插入圖片描述
其中跟我們講的資料代理牽扯最大的就是get和set方法。 瞭解了Object.defieProperty()方法後,我們自己來實現一個簡單的資料代理,直接貼程式碼:

let a = {
    data: {
        b: 123
    }
};
//目的:我們想通過a.b直接拿到b裡面的資料。

//引數target:代理者,引數sourceKey:被代理者
function proxy(target,sourceKey){
    let data = target[sourceKey];
    //拿到被代理者的所有屬性名
    let keys = Object.keys(data);
    //遍歷所有屬性名,把所有屬性名通過defindeProperty方法新增到代理者身上,並定義get和set方法,實現對資料的操作
    for (let i = 0, l = keys.length; i < l; i++) {
        let key = keys[i];
        Object.defineProperty(target, key, {
            enumerable: true,
            configurable: true,
            get() {
                return this[sourceKey][key];
            },
            set(val) {
                this[sourceKey][key] = val;
            }
        });
    }
}

proxy(a, "data");

console.log(a.b); // 123
複製程式碼

通過proxy函式,我們順利的完成了a對b的資料代理,是不是很簡單?

相關文章