上篇文章Mobx 源碼分析 - 熱身提到,observable
上綁定了 13 個方法。此篇文章會重點講解 shallowBox
和 box
。react
當調用 observable.shallowBox
時,mobx
會給出廢棄警告,並幫你轉換成 observable.box
,只是在轉換的時候,會給 observable.box
傳入第二個參數 { name, deep: false }
,這個參數的做用即是告訴 observable.box
在實例化 ObservableValue
時,使用 referenceEnhancer
。app
referenceEnhancer
禁用自動的 observable
轉換,只是建立一個 observable
引用。函數
相反的,若是咱們調用 observable.box
,並給其傳入 { deep: true }
。源碼分析
能夠看到,value
這時已是 ObservableValue
的實例。post
打開 types/observablevalue.ts
文件,該文件向外界暴露 ObservableValue
類和 isObservableValue
方法。ui
ObservableValue
類繼承 Atom
類。ObservableValue
類的構造函數接收 5 個參數,分別爲 value
、enhancer
、name
、notifySpy
和 equals
,其中 name
與 equals
存在默認值。name
沒什麼好說的,就是一個 id
,equals
的默認值爲 comparer.default
,comparer.default
主要用來判斷兩個值是否相等。Atom
構造函數,並把 value
值設爲傳遞進來的 enhancer
函數執行的結果。spy
數量,若是有,則發送一個事件。dehanceValue
、set
、prepareNewValue
、setNewValue
、get
、intercept
、observe
、toJSON
、toString
和 valueOf
。valueOf
方法。ObservableValue.prototype[primitiveSymbol()] = ObservableValue.prototype.valueOf
複製代碼
ObservableValue
類 8 個公共方法,2 個私有方法。this
接收一個回調函數 listener
和是否當即調用 fireImmediately
。若是 fireImmediately
爲 true
,則當即調用 listener
函數。spa
調用 registerListener
註冊監聽器,方法內部大部分與 registerInterceptor
實現相同。prototype
用來在任何變化應用前將其攔截。3d
方法內部調用 registerInterceptor
,registerInterceptor
函數內部會判斷實例上是否存在 interceptors
,若是不存在,則賦爲 []
,並把 handler
存入 interceptors
。最後返回一個函數,且該函數只能被調用一次。
export function registerInterceptor<T>( interceptable: IInterceptable<T>, handler: IInterceptor<T> ): Lambda {
...
return once(() => {
const idx = interceptors.indexOf(handler)
if (idx !== -1) interceptors.splice(idx, 1)
})
}
export function once(func: Lambda): Lambda {
let invoked = false
return function() {
if (invoked) return
invoked = true
return (func as any).apply(this, arguments)
}
}
複製代碼
返回當前值,具體內容講解會放在後面章節。
替換當前存儲的值並通知全部觀察者。
oldValue
,而後調用 prepareNewValue
方法生成新值 newValue
。newValue
是否等於 globalState.UNCHANGED
,若是等於什麼都不作,若是不等於,則判斷是否有監聽器 spy
,有則發送 spyReportStart
事件,沒有則什麼都不作。setNewValue
方法spyReportEnd
事件返回 this.get()
reportChanged
函數,這裏只瞭解大概,具體內容講解會放在後面章節。listener
,若是有,調用 notifyListeners
方法public reportChanged() {
// 開始處理事務
startBatch();
// derivation、reaction
propagateChanged(this);
// 結束處理事務
endBatch();
}
複製代碼
返回 ${this.name}[${this.value}]
返回 toPrimitive(this.get())
值得一提的是,方法內部會首先判斷是否有攔截器 interceptor
。
若是有則會依次調用攔截器方法,並判斷攔截器是否返回對象或 nothing,若是不是則報錯;若是是 nothing,則直接返回,下面的攔截器再也不調用;若是是對象,則繼續調用接下來的攔截器。
export function interceptChange<T>( interceptable: IInterceptable<T | null>, change: T | null ): T | null {
const prevU = untrackedStart()
try {
const interceptors = interceptable.interceptors
if (interceptors)
for (let i = 0, l = interceptors.length; i < l; i++) {
change = interceptors[i](change)
invariant(
!change || (change as any).type,
"Intercept handlers should return nothing or a change object"
)
if (!change) break
}
return change
} finally {
untrackedEnd(prevU)
}
}
複製代碼
若是返回的 change
爲 nothing,則直接返回 globalState.UNCHANGED
,不然取 change.newValue
做爲新值。接下來方法和沒有攔截器走的邏輯一致。
若是沒有攔截器,則調用 enhancer
方法生成新值,最後判斷舊值與新值是否相等,若是相等返回 globalState.UNCHANGED
,不然返回新值。
isObservableValue
函數是 createInstanceofPredicate
函數返回值。
var isObservableValue = createInstanceofPredicate("ObservableValue", ObservableValue);
複製代碼
mox
源碼閱讀起來,很難理解,須要細細品嚐。若是以爲寫得好不錯,還請鼓勵下,點個👍。