欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析一下Vue3的響應(yīng)式原理

 更新時(shí)間:2022年08月11日 14:10:04   作者:王岳  
這篇文章主要通過(guò)示例和大家一起淺析一下Vue3的響應(yīng)式原理,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Vue3有一定幫助,需要的可以參考一下

Proxy

Vue3 的響應(yīng)式原理依賴了 Proxy 這個(gè)核心 API,通過(guò) Proxy 可以劫持對(duì)象的某些操作。

const?obj?=?{?a:?1?};
const?p?=?new?Proxy(obj,?{
??get(target,?property,?receiver)?{
????console.log("get");
????return?Reflect.get(target,?property,?receiver);
??},
??set(target,?property,?value,?receiver)?{
????console.log("set");
????return?Reflect.set(target,?property,?receiver);
??},
??has(target,?prop)?{
????console.log("has");
????return?Reflect.has(target,?prop);
??},
??deleteProperty(target,?prop)?{
????console.log("deleteProperty");
????return?Reflect.deleteProperty(target,?prop);
??},
});

p.a;?//?輸出?-->?get
p.a?=?2;?//?輸出?-->?set
"a"?in?p;?//?輸出?-->?has
delete?p.a;?//?輸出?-->?deleteProperty

如上例子,我們用 Proxy 代理了 Obj 對(duì)象的屬性訪問(wèn)、屬性賦值、in 操作符、delete 的操作,并進(jìn)行 console.log 輸出。

Reflect

Reflect 是與 Proxy 搭配使用的一個(gè) API,當(dāng)我們劫持了某些操作時(shí),如果需要再把這些操作反射回去,那么就需要 Reflect 這個(gè) API。

由于我們攔截了對(duì)象的操作,所以這些操作該有的功能都喪失了,例如,訪問(wèn)屬性 p.a 應(yīng)該得到 a 屬性的值,但此時(shí)卻不會(huì)有任何結(jié)果,如果我們還想擁有攔截之前的功能,那我們就需要用 Reflect 反射回去。

const?obj?=?{?a:?1?};
const?p?=?new?Proxy(obj,?{
??get(target,?property,?receiver)?{
????console.log("get");
????return?Reflect.get(target,?property,?receiver);
??},
??set(target,?property,?value,?receiver)?{
????console.log("set");
????return?Reflect.set(target,?property,?receiver);
??},
??has(target,?prop)?{
????console.log("has");
????return?Reflect.has(target,?prop);
??},
??deleteProperty(target,?prop)?{
????console.log("deleteProperty");
????return?Reflect.deleteProperty(target,?prop);
??},
});

舉個(gè)例子

以下全文我們都會(huì)通過(guò)這個(gè)例子來(lái)講述 Vue3 響應(yīng)式的原理。

<div?id="app"></div>

<script>
??//?創(chuàng)建一個(gè)響應(yīng)式對(duì)象
??const?state?=?reactive({?counter:?1?});

??//?立即運(yùn)行一個(gè)函數(shù),當(dāng)響應(yīng)式對(duì)象的屬性發(fā)生改變時(shí)重新執(zhí)行。
??effect(()?=>?{
????document.querySelector("#app").innerHTML?=?state.counter;
??});

??//?2s?后視圖更新
??setTimeout(()?=>?{
????state.counter?+=?1;
??},?2000);
</script>

我們用 reactive 創(chuàng)建了一個(gè)響應(yīng)式對(duì)象 state,并調(diào)用了 effect 方法,該方法接受一個(gè)副作用函數(shù),effect 的執(zhí)行會(huì)立即調(diào)用副作用函數(shù),并將 state.counter 賦值給 #app.innerHTML;兩秒后,state.counter += 1,此時(shí),effect 的副作用函數(shù)會(huì)重新執(zhí)行,頁(yè)面也會(huì)變成 2.

內(nèi)部的執(zhí)行過(guò)程大概如下圖所示:

  • 調(diào)用 reactive() 返回一個(gè) Proxy 代理對(duì)象,并劫持對(duì)象的 get 與 set 操作
  • 調(diào)用 effect() 方法時(shí),會(huì)訪問(wèn)屬性 state.counter,此時(shí)會(huì)觸發(fā) proxy 的 get 操作。
  • get 方法會(huì)調(diào)用 track() 進(jìn)行依賴收集;建立一個(gè)對(duì)象(state)、屬性(counter)、effect 副作用函數(shù)的依賴關(guān)系;
  • set 方法會(huì)調(diào)用 trigger() 進(jìn)行依賴更新;通過(guò)對(duì)象(state)與屬性(coutner)找到對(duì)應(yīng)的 effect 副作用函數(shù),然后重新執(zhí)行。

reactive

reactive 會(huì)返回如下一個(gè) Proxy 對(duì)象

const?reactive?=?(target)?=>?{
??return?new?Proxy(target,?{
????get(target,?key,?receiver)?{
??????const?res?=?Reflect.get(target,?key,?receiver);

??????track(target,?key);?//?收集依賴

??????if?(isObject(res))?{
????????//?如果當(dāng)前獲取的屬性值是一個(gè)對(duì)象,則繼續(xù)將為此對(duì)象創(chuàng)建?Proxy?代理
????????return?reactive(res);
??????}

??????return?res;
????},

????set(target,?key,?value,?receiver)?{
??????Reflect.set(target,?key,?value,?receiver);
??????trigger(target,?key);?//?依賴更新
????},
??});
};

effect

let?activeEffect;
function?effect(fn)?{
??const?_effect?=?function?reactiveEffect()?{
????activeEffect?=?_effect;
????fn();
??};

??_effect();
}

首先定義全局的 activeEffect,它永遠(yuǎn)指向當(dāng)前正在執(zhí)行的 effect 副作用函數(shù)。effect 為 fn 創(chuàng)建一個(gè)內(nèi)部的副作用函數(shù),然后立即執(zhí)行,此時(shí)會(huì)觸發(fā)對(duì)象的 get 操作,調(diào)用 track() 方法。

effect(()?=>?{
??// effect 的立即執(zhí)行會(huì)訪問(wèn) state.counter,觸發(fā)了對(duì)象的 get 操作。
??document.querySelector("#app").innerHTML?=?state.counter;
});

track

track 會(huì)建立一個(gè) 對(duì)象(state) => 屬性(counter) => effect 的一個(gè)依賴關(guān)系

const?targetMap?=?new?WeakMap();
function?track(target,?key)?{
??if?(!activeEffect)?{
????return;
??}

??let?depsMap?=?targetMap.get(target);
??if?(!depsMap)?{
????targetMap.set(target,?(depsMap?=?new?Map()));
??}

??let?dep?=?depsMap.get(key);
??if?(!dep)?{
????depsMap.set(key,?(dep?=?new?Set()));
??}

??if?(!dep.has(activeEffect))?{
????dep.add(activeEffect);
??}
}

執(zhí)行完成成后我們得到一個(gè)如下的數(shù)據(jù)結(jié)構(gòu):

[?//?map?集合
??{
????key:?{counter:?1}?//?state?對(duì)象,
????value:?[?//?map?集合
??????{
????????key:?"counter",
????????value:?[?//?set
??????????function?reactiveEffect()?{}?//?effect?副作用函數(shù)
????????],
??????}
????],
??},
];

注意:當(dāng)我們調(diào)用 effect 時(shí),會(huì)將當(dāng)前的副作用函數(shù)賦值給全局的 activeEffect,所以此時(shí)我們可以正確關(guān)聯(lián)其依賴。

trigger

當(dāng)我們給 state.counter 賦值的時(shí)候就會(huì)觸發(fā)代理對(duì)象的 set 操作,從而調(diào)用 trigger 方法

setTimeout(()?=>?{
??//?給?counter?屬性賦值會(huì)觸發(fā)?set?操作
??state.counter?+=?1;
},?2000);
function?trigger(target,?key)?{
??const?depsMap?=?targetMap.get(target);
??if?(!depsMap)?return;

??const?effects?=?depsMap.get(key);
??effects?&&?effects.forEach((effect)?=>?effect());
}

以上就是淺析一下Vue3的響應(yīng)式原理的詳細(xì)內(nèi)容,更多關(guān)于Vue3響應(yīng)式原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論