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
复制代码
相关文章
相关标签/搜索