Mobx 源碼分析 - 熱身

前些天寫過一篇,可是感受文章條理過於混亂,索性重寫。算法

前言

mobx 是一個簡單、可擴展的狀態管理庫,它經過透明的函數響應式編程使得狀態管理變得簡單和可擴展。編程

起步

首先打開 mobx 入口文件 src/mobx.ts,能夠發現 mobx 的共放在四個文件夾內。api

  • api 文件夾, 公共模塊的大多數靜態方法
  • core 文件夾,mobx 大多數算法的實現
  • types 文件夾,存放如何讓對象、數組和值可觀察
  • utils 文件夾,公共方法

文件向外部暴露了許多方法,好比咱們常用的 observableactioncomputedtoJS 等。數組

observable

打開 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 種方法,其中 shallowBoxshallowArrayshallowMapshallowObject 已經廢棄。observable 每個屬性對應的方法都會定義在 observableFactoriespost

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 屬性中 refshallowdeepstruct 分別對應了 mobx 文件內四個 decorator,這幾個 decorator 又對應着 enhancerspa

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,不然判斷傳遞進來的 optionsdeep 是否爲 false,是則使用 referenceEnhancer,不然 deepEnhancer

function getEnhancerFromOptions(options: CreateObservableOptions): IEnhancer<any> {
    return options.defaultDecorator
        ? options.defaultDecorator.enhancer
        : options.deep === false
        ? referenceEnhancer
        : deepEnhancer
}
複製代碼

裝飾器

createObservable 方法接收 3 個參數:varg2arg3,各對應原型對象、屬性、描述符,若是不清楚爲何,能夠在個人另外一篇文章解讀 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
複製代碼
相關文章
相關標籤/搜索