當咱們寫
age = observable.box(12)
的時候,寫@observable age = 12
的時候,寫age = observable(12)
的時候,mobx
作了什麼?不知道有多少人仔細研究過,沒研究也沒關係,這篇文章就是帶你去了解,mobx
具體作了什麼?api
observable
上綁定了許多屬性,好比經常使用的 box
、map
和 array
。當咱們調用 observable.box
的時候,mobx
會首先判斷當前調用方式,若是當前的調用方式會 decorator
調用,則直接報錯。函數
if (arguments.length > 2) incorrectlyUsedAsDecorator("box")
複製代碼
爲何 mobx
能夠經過參數個數就能判斷出來當前是否爲 decorator
調用?那是由於若是經過裝飾器調用,會往函數內傳入 3 個參數,因此這邊經過判斷參數個數就能夠肯定當前是否爲 decorator
調用。源碼分析
相信你們都知道 box
方法還有第二個參數 (不單單只是 box
有),這個參數的做用主要用以判斷用哪個 enhancer
和 name
的值。post
最後返回 ObservableValue
實例。ui
new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals)
複製代碼
調用 observable
時候,等於調用 createObservable
。spa
const observable = createObservable
複製代碼
createObservable
接收 3 個參數,內部會對第二個參數進行判斷,若是爲 string
,則調用 deepDecorator
函數。3d
若是傳入的參數爲已監聽對象,則直接返回;若是不是基本數據類型,則根據參數類型調用不一樣的包裝方法,好比對於 array
調用 observable.array
。若是是 NaN
,直接返回。若是是基本數據類型,提醒用戶使用 observable.box
方法。code
咱們已經知道 mobx
對於咱們的代碼會作兩件不一樣的事,一種調用 deepDecorator
函數,一種實例化 ObservableValue
。對象
注意,這裏咱們只針對於傳入的值爲
number
類型討論,不一樣類型有不一樣的實現方式繼承
實例化 ObservableValue
,ObservableValue
類繼承 Atom
類,ObservableValue
內部重寫了 set
和 get
方法。
當訪問實例時,會向全局發出 reportObserved
事件,並把當前實例存到 derivation.newObserving
中,以便數據發生更改,通知 derivation
。在這裏,實例爲被觀察者,derivation
爲觀察者。
修改實例值時,會開啓事務處理,並向全部的觀察者推送這次事件,推送完成後結束事務處理。
究竟 mobx
是如何更新依賴關係?咱們以 autorun
舉例。
autorun(()=>{
console.log(age.get())
})
複製代碼
當咱們調用 autorun
時候,會在全局狀態中增長當前實例,也就是當前的 derivation
,autorun
參數執行時,會把 age
的值,也就是 ObservableValue
實例,推入到當前的 derivation
屬性中,derivation
會用 diffValue
來刷新當前依賴關係,保持依賴最新。
調用 createDecoratorForEnhancer
返回值,在原型上添加 __mobxDecorators
對象,此對象的每個屬性 ( 比方說 @observable age,這裏面的屬性就是 age ) 都會存放一些關鍵信息,並劫持屬性的 get
與 set
方法。
target.__mobxDecorators[prop] = {
prop,
propertyCreator,
descriptor,
decoratorTarget: target,
decoratorArguments
}
複製代碼
當訪問屬性,會在原型上添加 __mobxDidRunLazyInitializers
和 $mobx
。$mobx
內存放 ObservableObjectAdministration
實例,並在 $mobx.values
對應的每個屬性存放 ObservableValue
實例。
const observable = (adm.values[propName] = new ObservableValue(
newValue,
enhancer,
`${adm.name}.${propName}`,
false
))
複製代碼
並對於屬性的訪問和讀取會再次劫持,每當訪問,都會調用原型上 $mobx
中 read
和 write
方法。read
和 write
方法所作的事與 observable.box
內部 get
和 set
作的事情同樣。