前些天寫過一篇,可是感受文章條理過於混亂,索性重寫。算法
mobx
是一個簡單、可擴展的狀態管理庫,它經過透明的函數響應式編程使得狀態管理變得簡單和可擴展。編程
首先打開 mobx
入口文件 src/mobx.ts
,能夠發現 mobx
的共放在四個文件夾內。api
api
文件夾, 公共模塊的大多數靜態方法core
文件夾,mobx
大多數算法的實現types
文件夾,存放如何讓對象、數組和值可觀察utils
文件夾,公共方法文件向外部暴露了許多方法,好比咱們常用的 observable
、action
、computed
和 toJS
等。數組
打開 api/observable.ts
文件,找到下面代碼,能夠發現 observable
實際上就是 createObservable
,這裏就是整個 mobx
的起點。app
export const observable: IObservableFactory &
IObservableFactories & {
enhancer: IEnhancer<any>
} = createObservable as any
複製代碼
mobx
支持三種使用方法,一種爲方法調用 observable()
,一種爲指定方法調用,好比 observable.box()
,最後一種爲裝飾器 @observable
。這三個區別是方法調用和裝飾器調用會針對不一樣數據類型,實例化不一樣的構造函數。若是是數組,會返回一個 Observable Array
。函數
observable
屬性上共定義 13 種方法,其中 shallowBox
、shallowArray
、shallowMap
和 shallowObject
已經廢棄。observable
每個屬性對應的方法都會定義在 observableFactories
。post
Object.keys(observableFactories).forEach(name => (observable[name] = observableFactories[name]))
複製代碼
若是調用這些已廢棄方法,mobx
會自動幫你轉換成對應的方法,並給出警告。好比:ui
shallowBox<T = any>(value?: T, name?: string): IObservableValue<T> {
if (arguments.length > 2) incorrectlyUsedAsDecorator("shallowBox")
deprecated(`observable.shallowBox`, `observable.box(value, { deep: false })`)
return observable.box(value, { name, deep: false })
}
複製代碼
observableFactories
屬性中 ref
、shallow
、deep
、struct
分別對應了 mobx
文件內四個 decorator
,這幾個 decorator
又對應着 enhancer
。spa
observable
中每個方法內部都會首先判斷當前是否以 decorator
方式調用,若是是則會報錯,最後返回其對應的構造函數的實例(object
除外)。好比:code
box<T = any>(value?: T, options?: CreateObservableOptions): IObservableValue<T> {
if (arguments.length > 2) incorrectlyUsedAsDecorator("box")
const o = asCreateObservableOptions(options)
return new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals)
}
複製代碼
在這裏,asCreateObservableOptions
方法主要根據傳遞進來的 options
生成實例化 ObservableValue
所需參數。getEnhancerFromOptions
會根據所生成的參數來判斷應該用哪個 enhancer
。若是傳遞進來的 options
上有 defaultDecorator
,則使用 options.defaultDecorator.enhancer
,不然判斷傳遞進來的 options
上 deep
是否爲 false
,是則使用 referenceEnhancer
,不然 deepEnhancer
。
function getEnhancerFromOptions(options: CreateObservableOptions): IEnhancer<any> {
return options.defaultDecorator
? options.defaultDecorator.enhancer
: options.deep === false
? referenceEnhancer
: deepEnhancer
}
複製代碼
createObservable
方法接收 3 個參數:v
、 arg2
和 arg3
,各對應原型對象、屬性、描述符,若是不清楚爲何,能夠在個人另外一篇文章解讀 Babel 編譯後的 decorator 代碼找到答案。
方法開始會判斷第二個參數是否爲 string
,若是是則直接返回調用 deepDecorator
的結果。
function createObservable(v: any, arg2?: any, arg3?: any) {
if (typeof arguments[1] === "string") {
return deepDecorator.apply(null, arguments)
}
...
}
複製代碼
判斷傳入的第一個參數是否已是可觀察,若是是則直接返回。若是不是,則根據不一樣的數據類型,進行不一樣的指定方法調用。若是都不是,則報錯,並提示使用 observable.box
。
if (isObservable(v)) return v
const res = isPlainObject(v)
? observable.object(v, arg2, arg3)
: Array.isArray(v)
? observable.array(v, arg2)
: isES6Map(v)
? observable.map(v, arg2)
: isES6Set(v)
? observable.set(v, arg2)
: v
if (res !== v) return res
複製代碼