Mobx 源码初探 - observable(二)

上一节讲到,observable 不仅支持 decorator 方式,还支持方法调用。

observable

age = observable(12)
1

observable 共有 13 种方法,其中 shallowBoxshallowArrayshallowMapshallowObject 已经废弃。

img

  • boxshallowBoxarrayshallowArraymapshallowMapset 会判断参数是否大于 2,如果大于则报错。

  • object 会判断第二个参数是否为 string,如果不是则报错。

ref、shallow、deep、struct

refshallowdeepstruct 四个方法很有意思,其中 deep 对应的是 deepDecorator 方法,当我们调用 @observable.deep 就相当于调用 @observable,剩下的三个则对应不同的 enhancer

注:如果直接调用这个四个方法,会返回描述符,所以我们的调用方式仍然为 @observable.deep

enhancer

mobx 共有四个 enhancer 函数。

img

deepEnhancer

deepEnhancer 在上一节已经讲过,其是任何 observable 都使用的默认的调节器。它将任何(尚未成为 observable )数组,映射或纯对象克隆并转换为 observable 对象,并将其赋值给给定属性。

shallowEnhancer

只能与集合组合使用。将任何分配的集合转换为 observable,但该集合的值将按原样处理。

referenceEnhancer

不转换为 observable

function referenceEnhancer(newValue) {
    // never turn into an observable
    return newValue;
}
1
2
3
4

refStructEnhancer

就像 referenceEnhancer, 但会忽略结构上等于当前值的新值。

function refStructEnhancer(v, oldValue, name) {
    if (true && isObservable(v))
        throw "observable.struct should not be used with observable values";
    if (deepEqual(v, oldValue)) return oldValue;
    return v;
}
1
2
3
4
5
6

observable.box

用法

name = observable.box(2)
1

源码解读

observable.box 接收两个参数 valueoptions,方法内部首先判断是否以 decorator 方式调用,如果是则报错,否则调用 asCreateObservableOptions 生成 options

if (arguments.length > 2) incorrectlyUsedAsDecorator("box");
var o = asCreateObservableOptions(options);
return new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals);
1
2
3

asCreateObservableOptions 会校验传入的第二个参数格式,如果第二个参数为 nullundefined,则返回 defaultCreateObservableOptions。否则判断传入的类型是否为 stringobject,如果都不是,则报错,否则进行进一步的校验。

function asCreateObservableOptions(thing) {
    if (thing === null || thing === undefined) return defaultCreateObservableOptions;
    if (typeof thing === 'string') return { name: thing, deep: true };
    if (true) {
        if (typeof thing !== 'object') return fail('expected options object');
        Object.keys(thing).forEach(assertValidOption);
    }
    return thing;
}
1
2
3
4
5
6
7
8
9

observable.box 函数内部,同样也会调用 new ObservableValue 来生成 observable 数据,区别就是 enhancer 会根据传入的第二个参数判断使用使用哪种 enhancernotifySpytrue 和最后一个参数。

// observable.box
new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals);
// @observable
new ObservableValue(newValue, enhancer, adm.name + "." + propName, false);
1
2
3
4

ObservableValue

上一节我们提到了关于 ObservableValue 的一部分知识,这里会继续深入了解。ObservableValue 接收 value, enhancer, name, notifySpy, equals 几个参数。

由于传入的 notifySpytrue,所以相比 @observable 多走一个判断。它会首先判断当前全局是否有全局 spy 监听器,如果有,则发送一个事件,剩下的和 @observable 所做的事相同。

if (notifySpy && isSpyEnabled()) {
    // only notify spy if this is a stand-alone observable
    spyReport({ type: "create", name: _this.name, newValue: "" + _this.value });
}
1
2
3
4

observable.array

方法内部实例化 ObservableArrayObservableArray 继承 StubArrayStubArray 继承 Array

var extendStatics = function(d, b) {
    extendStatics =
        // IE <=10 无 Object.setPrototypeOf
        Object.setPrototypeOf ||
        // 用来判断是否支持 __proto__,__proto__ 不支持 IE <= 10,处于此类环境 ({ __proto__: [] }) instanceof Array 会返回 false
        ({ __proto__: [] } instanceof Array &&
            function(d, b) {
                d.__proto__ = b;
            }) ||
        function(d, b) {
            for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
        };
    return extendStatics(d, b);
};

function __extends(d, b) {
    extendStatics(d, b);
    function __() {
        this.constructor = d;
    }
    d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __());
}

var ObservableArray = (function(_super) {
    ...
    __extends(ObservableArray, _super);
    ...
})(StubArray);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

__proto__

我们从继承源码中看见这样一句代码,({ __proto__: [] } instanceof Array) ,这句代码啥意思呀?这是个什么造型啊,挺别致啊。我们在控制台打印下,发现输出 true,于是开始怀疑人生中。。。

img

MDN:__proto__的读取器(getter)暴露了一个对象的内部 [[Prototype]] 。对于使用对象字面量创建的对象,这个值是 Object.prototype。对于使用数组字面量创建的对象,这个值是 Array.prototype。对于functions,这个值是Function.prototype。

({ __proto__: [] } instanceof Array) // true
({ __proto__: {} } instanceof Object) // true
({ __proto__: function(){} } instanceof Function) // true
({ __proto__: 2 } instanceof Object) // true
({ __proto__: 'abc' } instanceof Object) // true
({ __proto__: true } instanceof Object) // true
({ __proto__: NaN } instanceof Object) // true
({ __proto__: null } instanceof Object) // false
Object.getPrototypeOf({ __proto__: null }) // null
1
2
3
4
5
6
7
8
9

在控制台可以看到 { __proto__: null },生成的对象没有原型链,这与我们通过 Object.create(null) 得到的结果是一致的。

我们开始怀疑是不是通过 {__proto__: []}Object.create([]) 得到的结果一致?由于 Object.create 第一个参数接收对象,故只测试以下情况。

Object.create([]) instanceof Array // true
Object.create({}) instanceof Object // true
Object.create(function(){}) instanceof Function // true
Object.getPrototypeOf(Object.create(null) ) // null
1
2
3
4

observable.map

return new ObservableMap(initialValues, getEnhancerFromOptions(o), o.name);
1

observable.set

return new ObservableSet(initialValues, getEnhancerFromOptions(o), o.name);
1

observable.object

return extendObservable({}, props, decorators, o);
1
最后更新: 8/21/2019, 5:53:59 PM