Vue2數(shù)據(jù)雙向綁定是通過(guò)采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式來(lái)實(shí)現(xiàn)的。通過(guò)Object.defineProperty()來(lái)劫持各個(gè)屬性的setter,getter。修改觸發(fā)set方法賦值,獲取觸發(fā)get方法取值,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的回調(diào)并通過(guò)數(shù)據(jù)劫持發(fā)布信息。
但是 Object.defineProperty() 只能對(duì)屬性進(jìn)行數(shù)據(jù)劫持,不能對(duì)整個(gè)對(duì)象進(jìn)行劫持,同理無(wú)法對(duì)數(shù)組進(jìn)行劫持。Vue 框架是通過(guò)遍歷數(shù)組和遞歸遍歷對(duì)象,從而達(dá)到利用 Object.defineProperty() 也能對(duì)對(duì)象和數(shù)組(部分方法的操作)進(jìn)行監(jiān)聽(tīng)。
Vue的數(shù)組響應(yīng)式是如何實(shí)現(xiàn)的?它是以Array.prototype為原型,創(chuàng)建了一個(gè)arrayMethods對(duì)象,使用Object.setPrototypeOf()強(qiáng)制讓數(shù)組指向arrayMethods,這樣就可以觸發(fā)我們?cè)赼rrayMethods中的改寫(xiě)的數(shù)組操作方法。
缺陷:a、無(wú)法檢測(cè)到對(duì)象屬性的新增或刪除。Vue2采用Vue.$set和Vue.$delete.
b、不能監(jiān)聽(tīng)數(shù)組的變化。vue在實(shí)現(xiàn)數(shù)組的響應(yīng)式時(shí),它使用了一些hack,把無(wú)法監(jiān)聽(tīng)數(shù)組的情況通過(guò)重寫(xiě)數(shù)組的部分方法來(lái)實(shí)現(xiàn)響應(yīng)式,這也只限制在數(shù)組的push/pop/shift/unshift/splice/sort/reverse七個(gè)方法,其他數(shù)組方法及數(shù)組的使用則無(wú)法檢測(cè)到。如直接修改值和獲取數(shù)組長(zhǎng)度。
Proxy,字面意思是代理,是ES6提供的一個(gè)新的API,用于修改某些操作的默認(rèn)行為,可以理解為在目標(biāo)對(duì)象之前做一層攔截,外部所有的訪問(wèn)都必須通過(guò)這層攔截,通過(guò)這層攔截可以做很多事情,比如對(duì)數(shù)據(jù)進(jìn)行過(guò)濾、修改或者收集信息之類。
ES6原生提供的Proxy構(gòu)造函數(shù),用法如下:
var proxy =new Proxy(obj, handler)
其中obj為Proxy要攔截的對(duì)象,handler用來(lái)定制攔截的操作,返回一個(gè)新的代理對(duì)象proxy;

vue3中利用Proxy實(shí)現(xiàn)數(shù)據(jù)讀取和設(shè)置時(shí)進(jìn)行攔截,在攔截trap中實(shí)現(xiàn)數(shù)據(jù)的依賴收集以及觸發(fā)視圖更新操作。
1)diff算法優(yōu)化
diff算法是虛擬DOM技術(shù)的必然產(chǎn)物,它會(huì)對(duì)新舊虛擬DOM作對(duì)比(即diff),然后將變化的地方更新在真實(shí)DOM上。
在Vue2.0當(dāng)中,當(dāng)數(shù)據(jù)發(fā)生變化,它就會(huì)新生成一個(gè)DOM樹(shù),并和之前的DOM樹(shù)進(jìn)行比較,找到不同的節(jié)點(diǎn)然后更新。但這比較的過(guò)程是全量的比較,也就是每個(gè)節(jié)點(diǎn)都會(huì)彼此比較。但其中很顯然的是,有些節(jié)點(diǎn)中的內(nèi)容是不會(huì)發(fā)生改變的,那我們對(duì)其進(jìn)行比較就肯定消耗了時(shí)間。
所以在Vue3.0當(dāng)中,就對(duì)這部分內(nèi)容進(jìn)行了優(yōu)化:在創(chuàng)建虛擬DOM樹(shù)的時(shí)候,會(huì)根據(jù)DOM中的內(nèi)容會(huì)不會(huì)發(fā)生變化,添加一個(gè)靜態(tài)標(biāo)記。那么之后在與上次虛擬節(jié)點(diǎn)進(jìn)行對(duì)比的時(shí)候,就只會(huì)對(duì)比這些帶有靜態(tài)標(biāo)記(patch flag)的節(jié)點(diǎn)。
patchFlag的類型:

2)hoistStatic 靜態(tài)提升
vue2中無(wú)論元素是否參與更新,每次都會(huì)重新創(chuàng)建,然后再渲染;
vue3對(duì)于不參與更新的元素,會(huì)做靜態(tài)提升,只會(huì)被創(chuàng)建一次,在渲染時(shí)直接復(fù)用即可。
3)cacheHandlers 事件偵聽(tīng)器緩存
默認(rèn)情況下onClick會(huì)被視為動(dòng)態(tài)綁定,所以每次都會(huì)去追蹤它的變化。
但是因?yàn)槭峭粋€(gè)函數(shù),所以沒(méi)有追蹤變化,直接緩存起來(lái)復(fù)用即可