Mobx 源码初探 - observable(一)

observable 同时支持 decorator 方式和方法调用方式。数组

// 示例
@observable name = '张三';
const temp = observable.box(20);
复制代码

在源码中能够发现 mobxobservable 上绑定了不少方法。缓存

Object.keys(observableFactories).forEach(function(name) {
    return (observable[name] = observableFactories[name]);
});
复制代码

本篇文章重点介绍 @observable 调用,其他的后续文章会继续讲解。app

@observable 有一个很强大的功能,它会对于不一样类型,应用不一样的转换规则。它到底是如何处理的?函数

createObservable

当咱们使用 @observable,实质上是调用了 createObservable 的返回的 deepDecorator 函数。ui

createObservable 接收 3 个参数 varg2arg3,这三个参数分别对应构造函数的原型对象、属性名、描述符。this

function createObservable(v, arg2, arg3) {
    // @observable someProp;
    if (typeof arguments[1] === 'string') {
        return deepDecorator.apply(null, arguments);
    }
    ...
}
复制代码

createDecoratorForEnhancer

deepDecorator 函数是 createDecoratorForEnhancer 的返回值,它把 deepEnhancer 做为参数传递进去。deepDecorator 的具体功能就是针对不一样类型使用不一样方式的 observablespa

var deepDecorator = createDecoratorForEnhancer(deepEnhancer);
复制代码

createDecoratorForEnhancer 函数会返回一个 res,因此说当调用 @observable 时候就是等于执行 res 函数,传递进去的 deepEnhancer 会做为 resenhancer 属性存在。code

createPropDecorator

createDecoratorForEnhancer 方法内部会经过 createPropDecorator 函数生成 rescreatePropDecorator 函数接收 2 个参数,第一个参数 propertyInitiallyEnumerable 设置为 true ( 内部写死 ),第二个参数 propertyCreator 为传递进来的函数。对象

createPropDecorator 函数返回 decoratorFactory 函数。看到这里,咱们先整理下,当咱们编写 @observable,实质上就是在调用 decoratorFactory 函数。继承

decoratorFactory

decoratorFactory 函数内部定义 decorator 函数,当调用时,会先判断当前的调用方式,若是是 @decorator 方式调用,则直接执行 decorator 函数,不然返回 decorator 函数。

decorator 函数内部会首先判断构造函数的原型对象上是否存在 __mobxDecorators 属性,若是不存在,则定义此属性,并经过 addHiddenProp 方法设置描述符。

function addHiddenProp(object, propName, value) {
    Object.defineProperty(object, propName, {
        enumerable: false,
        writable: true,
        configurable: true,
        value: value // 此时为空对象
    });
}
复制代码

当构造函数原型对象上存在 __mobxDecorators 属性,则执行下面代码。

target.__mobxDecorators[prop] = {
    prop: prop, // 属性名
    propertyCreator: propertyCreator, // 传递进来的函数
    descriptor: descriptor, // 描述符
    decoratorTarget: target, // 构造函数原型对象
    decoratorArguments: decoratorArguments // 此时为 []
};
复制代码

createPropertyInitializerDescriptor

最后经过调用 createPropertyInitializerDescriptor 函数为属性生成描述符。createPropertyInitializerDescriptor 函数内部会根据是否可枚举进行分类,并以属性名做为缓存对象的 key,生成的描述符做为 value 存在。

尤为须要注意的是,描述符中有 getset 方法,这两个方法内部都会首先调用 initializeInstance 方法,而后才执行对应的数据操做。

initializeInstance

initializeInstance 方法会首先判断原型对象是否 __mobxDidRunLazyInitializers 属性,若是存在,则后续都不执行。若是不存在,则会依次调用原型对象上 __mobxDecorators 属性对应的 propertyCreator 方法。

看到这里,可能有人就懵了,问 propertyCreator 方法哪来的?还记得咱们在调用 createPropDecorator 函数传递进去的第二个参数吗?这个方法就是那来的。propertyCreator 内部首先会判断属性描述符中是否存在 get,这里的属性描述符是原有的属性描述符,而不是封装后的。若是存在 get 方法,则报错,不然继续执行。判断描述符是否存在,不存在则设置初始值为 undefined,存在则继续判断是否有 initializer 方法,若是没有,则初始值为描述符的 value。若是有此方法,不然执行此方法,获取属性初始值。

var initialValue = descriptor
    ? descriptor.initializer
        ? descriptor.initializer.call(target)
        : descriptor.value
    : undefined;
复制代码

defineObservableProperty

初始值获取以后,调用 defineObservableProperty 方法,传入 target 构造函数原型对象、propertyName 属性名、initialValue 初始值和 enhancer ( deepEnhancer )。

function defineObservableProperty(target, propName, newValue, enhancer) {
    var adm = asObservableObject(target);
}
复制代码

asObservableObject

asObservableObject 方法会首先判断原型对象是否可扩展,若是不能够,则报错。其次根据必定规则生成 name,经过调用 new ObservableObjectAdministration(target, name, defaultEnhancer) 生成 adm 对象,此对象会绑在原型对象的 $mobx 上,并返回新生成的 adm 对象。

defineObservableProperty 首先会经过调用 asObservableObject 方法获取 adm 对象,判断原型对象上的属性是否可配置与可写,若是不能够,报错。判断新生成的 adm 对象上是否存在 interceptors 属性,且属性值得长度大于 0

若是不存在,则给 adm 对象的 values 属性赋值,值为 ObservableValue 的实例。

ObservableValue

ObservableValue 类继承 Atom 类,在实例化 ObservableValue 同时,会执行 enhancer 方法,在这里即为 deepEnhancer

var ObservableValue = (function(_super) {
    __extends(ObservableValue, _super);
    // 部分代码
    var _this = _super.call(this, name) || this;
    _this.value = enhancer(value, undefined, name);
})(Atom);
复制代码

deepEnhancer 会对原型对象进行判断,若是是 observable,直接返回原型对象;若是是数组,返回 observable.array 调用后结果;若是是对象,返回 observable.object 调用后结果;若是是 Map,返回 observable.map 调用后结果;若是是 Set,返回 observable.set 调用后结果;若是都不是,则直接返回传进来的 v

function deepEnhancer(v, _, name) {
    if (isObservable(v)) return v;
    if (Array.isArray(v)) return observable.array(v, { name: name });
    if (isPlainObject(v)) return observable.object(v, undefined, { name: name });
    if (isES6Map(v)) return observable.map(v, { name: name });
    if (isES6Set(v)) return observable.set(v, { name: name });
    return v;
}
复制代码

defineObservableProperty 方法最后会覆盖原型对象原有的属性描述符,并劫持 getset 操做。

Object.defineProperty(target, propName, generateComputedPropConfig(propName));

function generateComputedPropConfig(){
    // 部分
    return {
        configurable: true,
        enumerable: true,
        get: function() {
            return this.$mobx.read(this, propName);
        },
        set: function(v) {
            this.$mobx.write(this, propName, v);
        }
    }
}
复制代码

若是以为文章不错,对你有帮助,烦请点赞。

相关文章
相关标签/搜索