Vue 3 源碼解析 reactive (pre-alpha)

10.5號凌晨,發佈了vue 3的 pre-alpha源碼,出於我對Vue的熱愛,火燒眉毛的就從github上拉了源碼,想看看Vue 3 更新了哪些有趣的變化~~

Vue最讓人感興趣的天然是它的響應式拉~ Vue 3改變了Vue 2採用Object.defineProperty的方法去而採用Proxy的監聽模式vue

Proxy的官方定義是Proxy 對象用於定義基本操做的自定義行爲(如屬性查找,賦值,枚舉,函數調用等)react

Proxy的語法爲:git

let p = new Proxy(target, handler);複製代碼

target參數用於監聽的目標對象(能夠是任何類型的對象,包括原生數組,函數,甚至能夠是另外一個代理)

handler則是一個對象,其實最經常使用的則是set和get方法

由target的定義就能夠看出,proxy解決了Vue 2中不能監聽數組改變的缺點github

注:Vue 2中之因此能夠監聽到數組改變的緣由是由於對數組方法進行了從新的包裝,這七個方法分別爲push, pop,shift,unshift,splice,reverse,sort數組

Vue 3將Observer重命名爲reactivebash

在用法上,建議reactive監聽複雜類型的數據,而ref採用簡單類型的數據函數

爲何要這麼說呢?是由於ref源碼中有一個convert函數,它會先判斷value是否爲一個Object,若是爲一個Object的狀況下會調用reactive方法學習

源碼以下:ui

const convert = (val: any): any => (isObject(val) ? reactive(val) : val)複製代碼

簡單說了下reactive和ref的一點不一樣(ref我會在下一節文章中講解~),接下來仍是要說reactive的實現拉~(點題^∀^)this

reactive中會先判斷是否爲readonly,若是在readonly的狀況下,就返回readonly的target

if (readonlyToRaw.has(target)) {   
 return target  
}
if (readonlyValues.has(target)) { 
   return readonly(target)
}
return createReactiveObject(  
   target,   
   rawToReactive,
   reactiveToRaw,
   mutableHandlers,
   mutableCollectionHandlers
)複製代碼

最後調用了一個createReactiveObject方法,reactive的核心就是這個拉~,終於接觸到了核心,讓咱們來看看~~

我將createReactiveObject的源碼來進行分開講解

if (!isObject(target)) {
  if (__DEV__) {
    console.warn(`value cannot be made reactive: ${String(target)}`)  
    }  
    return target
}複製代碼

首先isObject就是判斷當前的target是否爲一個object類型,源碼以下:

export const isObject = (val: any): val is Record<any, any> =>  
    val !== null && typeof val === 'object'複製代碼

__DEV__是一個Boolean類型的全局變量,因此第一段代碼的意思就是當target不是對象的時候會出現「不能響應target值」的警告( ớ ₃ờ)

let observed = toProxy.get(target)
if (observed !== void 0) {
  return observed
}複製代碼

toProxy是一個WeakMap<any,any>類型,來看一下WeakMap接口的源碼~

interface WeakMap<K extends object, V> {   
   delete(key: K): boolean;   
   get(key: K): V | undefined;
   has(key: K): boolean;
   set(key: K, value: V): this;
}複製代碼

因此當target若是有相應的代理了就會返回target而再也不執行下去

注:void 運算符對給定的表達式進行求值,而後返回undefined,因此void 0undefined

if (toRaw.has(target)) {   
    return target
}複製代碼

toRaw的類型和toProxy同樣,也是WeakMap,這段代碼即判斷target已是proxy的狀況下會返回target

即:toProxy和toRaw咱們能夠經過他們找到代理過的數據是否存在(或經過代理數據找到原始數據)

接下來就是判斷target是否能夠監聽

if (!canObserve(target)) {
   return target
 }複製代碼

canObserve(target)的target類型必須是Object|Array|Map|Set|WeakMap|WeakSet

處理完了target,接下來就是handler拉 ≖‿≖✧

const handlers = collectionTypes.has(target.constructor)    
    ? collectionHandlers
    : baseHandlers複製代碼

const collectionTypes: Set<any> = new Set([Set, Map, WeakMap, WeakSet])複製代碼

能夠從collectionTypes中看出,若是target.constructor是collectionTypes中聲明的類型就執行collectionHandlers,不然就是baseHandlers

在處理完target和handler以後,就能夠建立Proxy對象拉(Proxy介紹看本文開頭)~(ง •̀_•́)ง

observed = new Proxy(target, handlers)
toProxy.set(target, observed)
toRaw.set(observed, target)
if (!targetMap.has(target)) {
  targetMap.set(target, new Map())
}
return observed複製代碼

最終用Proxy構造一個Proxy對象,返回observed對象,這時候,vue的響應式核心部分就差很少結束了~~

國慶結束拉,接下來回學校作畢設上課~,Vue 3的源碼剛發佈,複雜度不是過高很是方便閱讀,因此接下來會繼續看Vue源碼~

本文到這裏就結束拉~,若是哪裏寫的很差,麻煩你們幫我指出~,一塊兒學習,謝謝~ 

相關文章
相關標籤/搜索