響應(yīng)式系統(tǒng)的基本原理
Vue基于
Object.defineProperty來實(shí)現(xiàn)響應(yīng)式,對(duì)于Object.defineProperty大家就算不熟悉也聽說過,我之前的文章也詳細(xì)介紹過。
語法大家參考文檔即可。
在上次的Vue原理學(xué)習(xí)(一)中,我們畫了一張圖,其中有一個(gè)_init的過程,也就是new Vue之后。
而_init的過程,會(huì)對(duì)數(shù)據(jù)進(jìn)行響應(yīng)式的處理。
我們先來看看代碼:
function defineDispose(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true, // 可枚舉
configurable: true, // 可配置、可重寫
get: function() {
return val; // 返回value,在這里Vue會(huì)產(chǎn)生依賴收集
},
set: function(newVal) {
if(newVal === val) return
cb(newVal)
}
})
}
這里我們用一個(gè)函數(shù)對(duì)Object.property進(jìn)行了簡(jiǎn)單的封裝,并且在set的時(shí)候,調(diào)用了一個(gè)cb函數(shù)。
// cb函數(shù)
function cb (newVal) {
console.log('數(shù)據(jù)發(fā)生了更新: ' + newVal);
}
到這里,雖然代碼可以正常工作,但是依然是不夠的,我們需要在封裝一層observer。傳入一個(gè)value,也就是需要響應(yīng)式的對(duì)象,在通俗點(diǎn)說,就是new Vue()的時(shí)候, 傳入的那個(gè)參數(shù)對(duì)象。
function observer(value) {
Object.keys(value).forEach(key => {
// 調(diào)用defineDispose函數(shù)
defineDispose(value, key, value[key]);
})
}
這里,我們使用遍歷來對(duì)每個(gè)對(duì)象屬性進(jìn)行了Object.defineProperty處理,也就是響應(yīng)式處理,當(dāng)然,這個(gè)實(shí)際的過程會(huì)復(fù)雜很多,比如需要對(duì)數(shù)據(jù)類型判斷、算法處理等等。
最后,我們實(shí)現(xiàn)可以通過new Vue的方式來初始化對(duì)象:
class Vue{
// 構(gòu)造函數(shù)
constructor(options) {
this._data = options.data; // 只對(duì)data處理
observer(this._data); // 調(diào)用observer
}
}
最后我們來調(diào)用一下:
let vue = new Vue({
data: {
title: '中國(guó)第一艘國(guó)產(chǎn)航母13日清晨離開碼頭 開始海試'
}
});
// 更新數(shù)據(jù)
vue._data.title = '中超-恒大2-2華夏近4場(chǎng)不勝 魯能壓哨平權(quán)健';
// 此時(shí)會(huì)調(diào)用cb函數(shù)打印如下數(shù)據(jù):
// 數(shù)據(jù)發(fā)生了更新: 中超-恒大2-2華夏近4場(chǎng)不勝 魯能壓哨平權(quán)健
這里,我們對(duì)Vue的響應(yīng)式有了一個(gè)基本的認(rèn)識(shí),整個(gè)過程也為我們復(fù)習(xí)了Object.defineProperty。當(dāng)然,實(shí)際的過程會(huì)比這復(fù)雜的多。
在剛才的代碼中,我們發(fā)現(xiàn),必須使用_data的改變才可以,但是Vue中卻可以直接使用this.xxx,實(shí)際上Vue本質(zhì)也是 _data,只不過是使用了數(shù)據(jù)代理,將_data代理到了data上。
嗯嗯嗯嗯嗯。
以上筆記是我 閱讀 掘金小冊(cè) 所得。
鏈接:https://juejin.im/book/5a36661851882538e2259c0f?inviteCode=596197525188257fd215e23e