vue3響應(yīng)式原理代理與反射(vue3 響應(yīng)式原理)
本篇文章給大家談?wù)剉ue3響應(yīng)式原理代理與反射,以及vue3 響應(yīng)式原理對(duì)應(yīng)的知識(shí)點(diǎn),希望對(duì)各位有所幫助,不要忘了收藏本站喔。
本文目錄一覽:
- 1、【手把手教你搓Vue響應(yīng)式原理】(一)初識(shí)Vue響應(yīng)式
- 2、Proxy(vue響應(yīng)式原理:數(shù)據(jù)偵測(cè)--數(shù)據(jù)劫持和數(shù)據(jù)代理)
- 3、能說(shuō)說(shuō)vue的響應(yīng)式原理嗎?
- 4、手寫 Vue3 響應(yīng)式系統(tǒng):核心就一個(gè)數(shù)據(jù)結(jié)構(gòu)
- 5、vue響應(yīng)式原理是什么?
【手把手教你搓Vue響應(yīng)式原理】(一)初識(shí)Vue響應(yīng)式
在講這個(gè)之前,首先要明白一點(diǎn),這個(gè)所謂的響應(yīng)式,其實(shí)本身就是對(duì) MVVM 的理解。
MVVM 其實(shí)就是所謂的 Modal View ViewModal 。
簡(jiǎn)單理解,就是你的 data 中的數(shù)據(jù),和 template 模板中的界面,本身就是兩個(gè)東西。
但是, Vue 給你做了一層中間的 ViewModal ,讓視圖上的改變能反映到 data 中, data 中的改變能反映到視圖上。
在這個(gè)反映過(guò)程中,ViewModal就是視圖和數(shù)據(jù)的一個(gè)橋梁。
同樣是讓 a + 1 。
在 Vue 中,這個(gè)橋梁是你看不見(jiàn)的,因?yàn)? Vue 都幫你完成了視圖和數(shù)據(jù)的變化傳遞。
而 React 就是侵入式的,因?yàn)橐@式地聲明 setState ,通過(guò)它,來(lái)設(shè)置變量的同時(shí),設(shè)置視圖的改變。
所以,所謂的侵入式,其實(shí)就是對(duì)于橋梁的侵入。
所以, Vue 的神奇之處就在于,不需要我們手動(dòng)地顯示調(diào)用 setState ,也就是這個(gè)橋梁, Vue 已經(jīng)幫我們橋接上了。
要讓 data 改變的同時(shí),視圖也發(fā)生改變,所以,問(wèn)題的所在,就是我們需要監(jiān)聽(tīng),什么時(shí)候,這個(gè)變量發(fā)生了變量。
然而, ES5 中,就有那么一個(gè)特性,可以做到對(duì)于數(shù)據(jù)的劫持(監(jiān)聽(tīng))。
它就是 Object.defineProperty 。
Object.defineProperty( obj, prop, descriptor ) 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回此對(duì)象,與此同時(shí),它可以對(duì) 對(duì)象的一些額外底層的屬性進(jìn)行設(shè)置 。例如可以設(shè)置 writable , enumerable , configurable 等屬性。
后面的額外屬性設(shè)置,才是我們使用它的重點(diǎn)。
但是,我們使用的不是上面的幾個(gè)屬性,最主要的還是它的 get set ,可以對(duì)屬性值的獲取和設(shè)置操作進(jìn)行攔截。
get主要是可以對(duì)值的獲取進(jìn)行攔截,,它必須要傳入一個(gè) return ,并且, 該函數(shù)的返回值會(huì)被用作屬性的值 。我們可以來(lái)看一個(gè)例子:
由于設(shè)置了 get ,所以,輸出 a.name 的時(shí)候直接會(huì)被攔截,走 get() 中的 return 所以,此時(shí), a.name 的值應(yīng)該是 你已經(jīng)被攔截了!。
set主要是可以對(duì)值的設(shè)置進(jìn)行攔截,該方法會(huì)接受一個(gè)參數(shù),那就是 被賦予的新值 。我們可以來(lái)看一個(gè)例子:
由于設(shè)置了 set ,所以,設(shè)置值的時(shí)候會(huì)被攔截,走 set() 中的方法。
所以, Vue 能自動(dòng)獲取data中的改變,反映到視圖的原因,就是有對(duì)于變量的獲取和設(shè)置的劫持,當(dāng)變量發(fā)生改變的同時(shí), Vue 能在第一時(shí)間知道,并且對(duì)視圖做出相應(yīng)的改變操作。
而這把鑰匙就是 Object.defineProperty 。
【尚硅谷】Vue源碼解析之?dāng)?shù)據(jù)響應(yīng)式原理
Object.defineProperty() - MDN
Proxy(vue響應(yīng)式原理:數(shù)據(jù)偵測(cè)--數(shù)據(jù)劫持和數(shù)據(jù)代理)
Object.defineProperty : 通過(guò)設(shè)定對(duì)象屬性getter/setter方法來(lái)監(jiān)聽(tīng)數(shù)據(jù)的變化,同時(shí)getter也用于依賴收集,而setter在數(shù)據(jù)變更時(shí)通知訂閱者更新視圖。
1.無(wú)法檢測(cè)到對(duì)象屬性的新增或刪除
由于js的動(dòng)態(tài)性,可以為對(duì)象追加新的屬性或者刪除其中某個(gè)屬性,這點(diǎn)對(duì)經(jīng)過(guò)Object.defineProperty方法建立的響應(yīng)式對(duì)象來(lái)說(shuō),只能追蹤對(duì)象已有數(shù)據(jù)是否被修改,無(wú)法追蹤新增屬性和刪除屬性,這就需要另外處理。
2.不能監(jiān)聽(tīng)數(shù)組的變化
vue在實(shí)現(xiàn)數(shù)組的響應(yīng)式時(shí),它使用了一些hack,把無(wú)法監(jiān)聽(tīng)數(shù)組的情況通過(guò)重寫數(shù)組的部分方法來(lái)實(shí)現(xiàn)響應(yīng)式,這也只限制在數(shù)組的push/pop/shift/unshift/splice/sort/reverse七個(gè)方法,其他數(shù)組方法及數(shù)組的使用則無(wú)法檢測(cè)到。
Proxy,字面意思是代理,是ES6提供的一個(gè)新的API,用于修改某些操作的默認(rèn)行為,可以理解為在目標(biāo)對(duì)象之前做一層攔截,外部所有的訪問(wèn)都必須通過(guò)這層攔截,通過(guò)這層攔截可以做很多事情,比如對(duì)數(shù)據(jù)進(jìn)行過(guò)濾、修改或者收集信息之類。借用 proxy的巧用 的一幅圖,它很形象的表達(dá)了Proxy的作用。
ES6原生提供的Proxy構(gòu)造函數(shù),用法如下:
其中obj為Proxy要攔截的對(duì)象,handler用來(lái)定制攔截的操作,返回一個(gè)新的代理對(duì)象proxy;Proxy代理特點(diǎn):
1.Proxy的代理針對(duì)的是整個(gè)對(duì)象,而不是像Object.defineProperty針對(duì)某個(gè)屬性。只需做一層代理就可以監(jiān)聽(tīng)同級(jí)結(jié)構(gòu)下的所有屬性變化,包括新增屬性和刪除屬性
2.Proxy也可以監(jiān)聽(tīng)數(shù)組的變化
參考:
能說(shuō)說(shuō)vue的響應(yīng)式原理嗎?
Vue 是一個(gè) MVVM 框架,核心是雙向數(shù)據(jù)綁定,VM(視圖模型)是作為 V(視圖) 和 M(模型)的橋梁。下面是對(duì) Vue 響應(yīng)式(雙向數(shù)據(jù)綁定)的理解,如果錯(cuò)誤盡請(qǐng)指出,一起交流,共同進(jìn)步。
Vue響應(yīng)式原理核心是 數(shù)據(jù)劫持,采用 ES5 的 object.defineproperty 的 getter 和 setter 方法。從一個(gè)例子出發(fā):
首先,在Vue初始化階段,通過(guò) observer 對(duì) data 中的屬性進(jìn)行遞歸的劫持,包括 name、job_ undergo、a、b等
在 get階段也就是初始化視圖時(shí),為每一個(gè)劫持的屬性分配一個(gè) 依賴收集器,主要收集當(dāng)前屬性的觀察者對(duì)象,例子中 name 屬性在模板中有兩處被使用,那么 name 屬性的依賴收集器中就存放兩個(gè)觀察者對(duì)象
當(dāng)點(diǎn)擊按鈕時(shí),將 name 修改為 lisi 時(shí),會(huì)觸發(fā) observer 的 setter 函數(shù),將 value 更新為 lisi 最新值,然后通知依賴收集器數(shù)據(jù)發(fā)生了更新。
依賴收集就是發(fā)布訂閱模式,依賴收集器會(huì)通知所有的觀察者對(duì)象,當(dāng)前name 屬性有兩個(gè)觀察者對(duì)象。
觀察者對(duì)象調(diào)用對(duì)應(yīng)的回調(diào)函數(shù)進(jìn)行相關(guān)的處理和DOM更新
以上是純響應(yīng)式原理的分析和總結(jié),下面配一張流程圖:
手寫 Vue3 響應(yīng)式系統(tǒng):核心就一個(gè)數(shù)據(jù)結(jié)構(gòu)
響應(yīng)式是 Vue 的特色,如果你簡(jiǎn)歷里寫了 Vue 項(xiàng)目,那基本都會(huì)問(wèn)響應(yīng)式實(shí)現(xiàn)原理。
而且不只是 Vue,狀態(tài)管理庫(kù) Mobx 也是基于響應(yīng)式實(shí)現(xiàn)的。
那響應(yīng)式是具體怎么實(shí)現(xiàn)的呢?
與其空談原理,不如讓我們來(lái)手寫一個(gè)簡(jiǎn)易版吧。
響應(yīng)式
首先,什么是響應(yīng)式呢?
響應(yīng)式就是被觀察的數(shù)據(jù)變化的時(shí)候做一系列聯(lián)動(dòng)處理。
就像一個(gè) 社會(huì) 熱點(diǎn)事件,當(dāng)它有消息更新的時(shí)候,各方媒體都會(huì)跟進(jìn)做相關(guān)報(bào)道。
這里 社會(huì) 熱點(diǎn)事件就是被觀察的目標(biāo)。
那在前端框架里,這個(gè)被觀察的目標(biāo)是什么呢?
很明顯,是狀態(tài)。
狀態(tài)一般是多個(gè),會(huì)通過(guò)對(duì)象的方式來(lái)組織。所以,我們觀察狀態(tài)對(duì)象的每個(gè) key 的變化,聯(lián)動(dòng)做一系列處理就可以了。
我們要維護(hù)這樣的數(shù)據(jù)結(jié)構(gòu):
圖片
狀態(tài)對(duì)象的每個(gè) key 都有關(guān)聯(lián)的一系列 effect 副作用函數(shù),也就是變化的時(shí)候聯(lián)動(dòng)執(zhí)行的邏輯,通過(guò) Set 來(lái)組織。
每個(gè) key 都是這樣關(guān)聯(lián)了一系列 effect 函數(shù),那多個(gè) key 就可以放到一個(gè) Map 里維護(hù)。
這個(gè) Map 是在對(duì)象存在的時(shí)候它就存在,對(duì)象銷毀的時(shí)候它也要跟著銷毀。(因?yàn)閷?duì)象都沒(méi)了自然也不需要維護(hù)每個(gè) key 關(guān)聯(lián)的 effect 了)
而 WeakMap 正好就有這樣的特性,WeakMap 的 key 必須是一個(gè)對(duì)象,value 可以是任意數(shù)據(jù),key 的對(duì)象銷毀的時(shí)候,value 也會(huì)銷毀。
所以,響應(yīng)式的 Map 會(huì)用 WeakMap 來(lái)保存,key 為原對(duì)象。
這個(gè)數(shù)據(jù)結(jié)構(gòu)就是響應(yīng)式的核心數(shù)據(jù)結(jié)構(gòu)了。
比如這樣的狀態(tài)對(duì)象:
const obj = {
a: 1,
b: 2
}
它的響應(yīng)式數(shù)據(jù)結(jié)構(gòu)就是這樣的:
const depsMap = new Map();
const aDeps = new Set();
depsMap.set('a', aDeps);
const bDeps = new Set();
depsMap.set('b', bDeps);
const reactiveMap = new WeakMap()
reactiveMap.set(obj, depsMap);
創(chuàng)建出的數(shù)據(jù)結(jié)構(gòu)就是圖中的那個(gè):
圖片
圖片
然后添加 deps 依賴,比如一個(gè)函數(shù)依賴了 a,那就要添加到 a 的 deps 集合里:
effect(() = {
console.log(obj.a);
});
也就是這樣:
const depsMap = reactiveMap.get(obj);
const aDeps = depsMap.get('a');
aDeps.add(該函數(shù));
這樣維護(hù) deps 功能上沒(méi)啥問(wèn)題,但是難道要讓用戶手動(dòng)添加 deps 么?
那不但會(huì)侵入業(yè)務(wù)代碼,而且還容易遺漏。
所以肯定不會(huì)讓用戶手動(dòng)維護(hù) deps,而是要做自動(dòng)的依賴收集。
那怎么自動(dòng)收集依賴呢?
讀取狀態(tài)值的時(shí)候,就建立了和該狀態(tài)的依賴關(guān)系,所以很容易想到可以代理狀態(tài)的 get 來(lái)實(shí)現(xiàn)。
通過(guò) Object.defineProperty 或者 Proxy 都可以:
const data = {
a: 1,
b: 2
}
let activeEffect
function effect(fn) {
activeEffect = fn
fn()
}
const reactiveMap = new WeakMap()
const obj = new Proxy(data, {
get(targetObj, key) {
let depsMap = reactiveMap.get(targetObj);
if (!depsMap) {
reactiveMap.set(targetObj, (depsMap = new Map()))
}
let deps = depsMap.get(key)
if (!deps) {
depsMap.set(key, (deps = new Set()))
}
deps.add(activeEffect)
return targetObj[key]
}
})
effect 會(huì)執(zhí)行傳入的回調(diào)函數(shù) fn,當(dāng)你在 fn 里讀取 obj.a 的時(shí)候,就會(huì)觸發(fā) get,會(huì)拿到對(duì)象的響應(yīng)式的 Map,從里面取出 a 對(duì)應(yīng)的 deps 集合,往里面添加當(dāng)前的 effect 函數(shù)。
這樣就完成了一次依賴收集。
當(dāng)你修改 obj.a 的時(shí)候,要通知所有的 deps,所以還要代理 set:
set(targetObj, key, newVal) {
targetObj[key] = newVal
const depsMap = reactiveMap.get(targetObj)
if (!depsMap) return
const effects = depsMap.get(key)
effects effects.forEach(fn = fn())
}
基本的響應(yīng)式完成了,我們測(cè)試一下:
圖片
打印了兩次,第一次是 1,第二次是 3。
effect 會(huì)先執(zhí)行一次傳入的回調(diào)函數(shù),觸發(fā) get 來(lái)收集依賴,這時(shí)候打印的 obj.a 是 1
然后當(dāng) obj.a 賦值為 3 后,會(huì)觸發(fā) set,執(zhí)行收集的依賴,這時(shí)候打印 obj.a 是 3
依賴也正確收集到了:
圖片
結(jié)果是對(duì)的,我們完成了基本的響應(yīng)式!
當(dāng)然,響應(yīng)式不會(huì)只有這么點(diǎn)代碼的,我們現(xiàn)在的實(shí)現(xiàn)還不完善,還有一些問(wèn)題。
比如,如果代碼里有分支切換,上次執(zhí)行會(huì)依賴 obj.b 下次執(zhí)行又不依賴了,這時(shí)候是不是就有了無(wú)效的依賴?
這樣一段代碼:
const obj = {
a: 1,
b: 2
}
effect(() = {
console.log(obj.a ? obj.b : 'nothing');
});
obj.a = undefined;
obj.b = 3;
第一次執(zhí)行 effect 函數(shù),obj.a 是 1,這時(shí)候會(huì)走到第一個(gè)分支,又依賴了 obj.b。
把 obj.a 修改為 undefined,觸發(fā) set,執(zhí)行所有的依賴函數(shù),這時(shí)候走到分支二,不再依賴 obj.b。
把 obj.b 修改為 3,按理說(shuō)這時(shí)候沒(méi)有依賴 b 的函數(shù)了,我們執(zhí)行試一下:
圖片
第一次打印 2 是對(duì)的,也就是走到了第一個(gè)分支,打印 obj.b
第二次打印 nothing 也是對(duì)的,這時(shí)候走到第二個(gè)分支。
但是第三次打印 nothing 就不對(duì)了,因?yàn)檫@時(shí)候 obj.b 已經(jīng)沒(méi)有依賴函數(shù)了,但是還是打印了。
打印看下 deps,會(huì)發(fā)現(xiàn) obj.b 的 deps 沒(méi)有清除
圖片
所以解決方案就是每次添加依賴前清空下上次的 deps。
怎么清空某個(gè)函數(shù)關(guān)聯(lián)的所有 deps 呢?
記錄下就好了。
我們改造下現(xiàn)有的 effect 函數(shù):
let activeEffect
function effect(fn) {
activeEffect = fn
fn()
}
記錄下這個(gè) effect 函數(shù)被放到了哪些 deps 集合里。也就是:
let activeEffect
function effect(fn) {
const effectFn = () = {
activeEffect = effectFn
fn()
}
effectFn.deps = []
effectFn()
}
對(duì)之前的 fn 包一層,在函數(shù)上添加個(gè) deps 數(shù)組來(lái)記錄被添加到哪些依賴集合里。
get 收集依賴的時(shí)候,也記錄一份到這里:
圖片
這樣下次再執(zhí)行這個(gè) effect 函數(shù)的時(shí)候,就可以把這個(gè) effect 函數(shù)從上次添加到的依賴集合里刪掉:
圖片
cleanup 實(shí)現(xiàn)如下:
function cleanup(effectFn) {
for (let i = 0; i effectFn.deps.length; i++) {
const deps = effectFn.deps[i]
deps.delete(effectFn)
}
effectFn.deps.length = 0
}
effectFn.deps 數(shù)組記錄了被添加到的 deps 集合,從中刪掉自己。
全刪完之后就把上次記錄的 deps 數(shù)組置空。
我們?cè)賮?lái)測(cè)試下:
圖片
無(wú)限循環(huán)打印了,什么鬼?
問(wèn)題出現(xiàn)在這里:
圖片
set 的時(shí)候會(huì)執(zhí)行所有的當(dāng)前 key 的 deps 集合里的 effect 函數(shù)。
而我們執(zhí)行 effect 函數(shù)之前會(huì)把它從之前的 deps 集合中清掉:
圖片
執(zhí)行的時(shí)候又被添加到了 deps 集合。
這樣 delete 又 add,delete 又 add,所以就無(wú)限循環(huán)了。
解決的方式就是創(chuàng)建第二個(gè) Set,只用于遍歷:
圖片
這樣就不會(huì)無(wú)限循環(huán)了。
再測(cè)試一次:
圖片
現(xiàn)在當(dāng) obj.a 賦值為 undefined 之后,再次執(zhí)行 effect 函數(shù),obj.b 的 deps 集合就被清空了,所以需改 obj.b 也不會(huì)打印啥。
看下現(xiàn)在的響應(yīng)式數(shù)據(jù)結(jié)構(gòu):
圖片
確實(shí),b 的 deps 集合被清空了。
那現(xiàn)在的響應(yīng)式實(shí)現(xiàn)是完善的了么?
也不是,還有一個(gè)問(wèn)題:
如果 effect 嵌套了,那依賴還能正確的收集么?
首先講下為什么要支持 effect 嵌套,因?yàn)榻M件是可以嵌套的,而且組件里會(huì)寫 effect,那也就是 effect 嵌套了,所以必須支持嵌套。
我們嵌套下試試:
effect(() = {
console.log('effect1');
effect(() = {
console.log('effect2');
obj.b;
});
obj.a;
});
obj.a = 3;
按理說(shuō)會(huì)打印一次 effect1、一次 effect2,這是最開(kāi)始的那次執(zhí)行。
然后 obj.a 修改為 3 后,會(huì)觸發(fā)一次 effect1 的打印,執(zhí)行內(nèi)層 effect,又觸發(fā)一次 effect2 的打印。
也就是會(huì)打印 effect1、effect2、effect1、effect2。
我們測(cè)試下:
圖片
打印了 effect1、effet2 這是對(duì)的,但第三次打印的是 effect2,這說(shuō)明 obj.a 修改后并沒(méi)有執(zhí)行外層函數(shù),而是執(zhí)行的內(nèi)層函數(shù)。
為什么呢?
看下這段代碼:
圖片
我們執(zhí)行 effect 的時(shí)候,會(huì)把它賦值給一個(gè)全局變量 activeEffect,然后后面收集依賴就用的這個(gè)。
當(dāng)嵌套 effect 的時(shí)候,內(nèi)層函數(shù)執(zhí)行后會(huì)修改 activeEffect 這樣收集到的依賴就不對(duì)了。
怎么辦呢?
嵌套的話加一個(gè)棧來(lái)記錄 effect 不就行了?
也就是這樣:
圖片
執(zhí)行 effect 函數(shù)前把當(dāng)前 effectFn 入棧,執(zhí)行完以后出棧,修改 activeEffect 為棧頂?shù)?effectFn。
這樣就保證了收集到的依賴是正確的。
這種思想的應(yīng)用還是很多的,需要保存和恢復(fù)上下文的時(shí)候,都是這樣加一個(gè)棧。
我們?cè)贉y(cè)試一下:
圖片
現(xiàn)在的打印就對(duì)了。
至此,我們的響應(yīng)式系統(tǒng)就算比較完善了。
全部代碼如下:
const data = {
a: 1,
b: 2
}
let activeEffect
const effectStack = [];
function effect(fn) {
const effectFn = () = {
cleanup(effectFn)
activeEffect = effectFn
effectStack.push(effectFn);
fn()
effectStack.pop();
activeEffect = effectStack[effectStack.length - 1];
}
effectFn.deps = []
effectFn()
}
function cleanup(effectFn) {
for (let i = 0; i effectFn.deps.length; i++) {
const deps = effectFn.deps[i]
deps.delete(effectFn)
}
effectFn.deps.length = 0
}
const reactiveMap = new WeakMap()
const obj = new Proxy(data, {
get(targetObj, key) {
let depsMap = reactiveMap.get(targetObj)
if (!depsMap) {
reactiveMap.set(targetObj, (depsMap = new Map()))
}
let deps = depsMap.get(key)
if (!deps) {
depsMap.set(key, (deps = new Set()))
}
deps.add(activeEffect)
activeEffect.deps.push(deps);
return targetObj[key]
},
set(targetObj, key, newVal) {
targetObj[key] = newVal
const depsMap = reactiveMap.get(targetObj)
if (!depsMap) return
const effects = depsMap.get(key)
// effects effects.forEach(fn = fn())
const effectsToRun = new Set(effects);
effectsToRun.forEach(effectFn = effectFn());
}
})
總結(jié)
響應(yīng)式就是數(shù)據(jù)變化的時(shí)候做一系列聯(lián)動(dòng)的處理。
核心是這樣一個(gè)數(shù)據(jù)結(jié)構(gòu):
圖片
最外層是 WeakMap,key 為對(duì)象,value 為響應(yīng)式的 Map。這樣當(dāng)對(duì)象銷毀時(shí),Map 也會(huì)銷毀。
Map 里保存了每個(gè) key 的依賴集合,用 Set 組織。
我們通過(guò) Proxy 來(lái)完成自動(dòng)的依賴收集,也就是添加 effect 到對(duì)應(yīng) key 的 deps 的集合里。set 的時(shí)候觸發(fā)所有的 effect 函數(shù)執(zhí)行。
這就是基本的響應(yīng)式系統(tǒng)。
但是還不夠完善,每次執(zhí)行 effect 前要從上次添加到的 deps 集合中刪掉它,然后重新收集依賴。這樣可以避免因?yàn)榉种袚Q產(chǎn)生的無(wú)效依賴。
并且執(zhí)行 deps 中的 effect 前要?jiǎng)?chuàng)建一個(gè)新的 Set 來(lái)執(zhí)行,避免 add、delete 循環(huán)起來(lái)。
此外,為了支持嵌套 effect,需要在執(zhí)行 effect 之前把它推到棧里,然后執(zhí)行完出棧。
解決了這幾個(gè)問(wèn)題之后,就是一個(gè)完善的 Vue 響應(yīng)式系統(tǒng)了。
當(dāng)然,現(xiàn)在雖然功能是完善的,但是沒(méi)有實(shí)現(xiàn) computed、watch 等功能,之后再實(shí)現(xiàn)。
最后,再來(lái)看一下這個(gè)數(shù)據(jù)結(jié)構(gòu),理解了它就理解了 vue 響應(yīng)式的核心:
圖片
vue響應(yīng)式原理是什么?
當(dāng)一個(gè)vue實(shí)例加載時(shí),會(huì)進(jìn)行初始化,將他的配置項(xiàng)options和mixins的內(nèi)容合并,以options為主,而在初始化data時(shí),會(huì)對(duì)data對(duì)象進(jìn)行數(shù)據(jù)劫持,并做代理,通過(guò)Object。
definproperty劫持?jǐn)?shù)據(jù)后vue會(huì)查找當(dāng)前屬性有無(wú)依賴項(xiàng)既被watch,或者依賴當(dāng)前屬性的值,如果有,就會(huì)注冊(cè)依賴既deps,而注冊(cè)deps時(shí)會(huì)在wather內(nèi)添加新的更新目標(biāo)。
當(dāng)數(shù)據(jù)發(fā)生變更時(shí),會(huì)觸發(fā)deps的更新方法,調(diào)用所有的watcher,watcher又會(huì)觸發(fā)對(duì)應(yīng)deps的更新,直到所有依賴項(xiàng)更新完畢。
擴(kuò)展資料:
Vue 是一個(gè) MVVM框架,核心是雙向數(shù)據(jù)綁定,VM(視圖模型)是作為V(視圖)和M(模型)的橋梁。對(duì)Vue響應(yīng)式(雙向數(shù)據(jù)綁定)的理解,如果錯(cuò)誤盡請(qǐng)指出,一起交流,共同進(jìn)步。Vue響應(yīng)式原理核心是 數(shù)據(jù)劫持,采用 ES5 的 object.defineproperty 的 getter 和 setter 方法。
Vue.js 最顯著的一個(gè)功能是響應(yīng)系統(tǒng) —— 模型只是普通對(duì)象,修改它則更新視圖。這讓狀態(tài)管理非常簡(jiǎn)單且直觀,不過(guò)理解它的原理也很重要,可以避免一些常見(jiàn)問(wèn)題。下面我們開(kāi)始深挖 Vue.js 響應(yīng)系統(tǒng)的底層細(xì)節(jié)。
參考資料來(lái)源:百度百科-Vue·js前端開(kāi)發(fā)技術(shù)
關(guān)于vue3響應(yīng)式原理代理與反射和vue3 響應(yīng)式原理的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
掃描二維碼推送至手機(jī)訪問(wèn)。
版權(quán)聲明:本文由飛速云SEO網(wǎng)絡(luò)優(yōu)化推廣發(fā)布,如需轉(zhuǎn)載請(qǐng)注明出處。