Above, we speculated on the basic principles of Mobx and simulated the implementation of two core Mobx apis. In this article, we will enter the source code to see how Observable is implemented.

Not simple Observable

An Observable isn’t just a method. It should be thought of as an object.

Mobx definition of observables on the packages/Mobx/SRC/API/observables. Ts:

function createObservable(v: any, arg2? :any, arg3? :any) {}
Object.assign(createObservable, observableDecoratorAnnotation)
export var observable: IObservableFactory = assign(createObservable, observableFactories)
Copy the code

After doing this, an Observable can be called as a method and has these capabilities:

const observable = function(){... } Object.assign(observable,{ box(){}, array() {}, map() {}, set() {}, object() {}, ref: ... , shallow: ... , deep: ... , struct: ... , annotationType_: ... , options_: ... , make_(){}, extend_(){} })Copy the code

The four properties from createObservableAnnotation methods to create objects

    {
        annotationType_: name,
        options_: options,
        make_,
        extend_
    }
Copy the code

The other properties come from the observableFactories object.

The body of an Observable looks like this:

function createObservable(v: any, arg2? :any, arg3? :any) {...if (isObservable(v)) return v
    // plain object
    if (isPlainObject(v)) return observable.object(v, arg2, arg3)
    // Array
    if (Array.isArray(v)) return observable.array(v, arg2)
    ...
    return observable.box(v, arg2)
}
Copy the code

Observable calls the corresponding method based on the parameter type:

observable.object

Suppose we call form observables (obj), obj is a plain object, it is the actual call observableFactories. Object, it returns a value is as follows:

 extendObservable(
    globalState.useProxies === false|| options? .proxy ===false
        ? asObservableObject({}, options)
        : asDynamicObservableObject({}, options),
    props,
    decorators
)
Copy the code

You can see that the returned value was created from an empty object {}.

, according to whether to use the Proxy to invoke asDynamicObservableObject and asObservableObject respectively to the empty object for processing.

AsObservableObject and extendObservable

AsObservableObject for this added a ${} object mobx properties, it is a ObservableObjectAdministration instance. This object will be called target later

export function asObservableObject( target: any, options? : CreateObservableOptions ): IIsObservableObject { if (hasProp(target, $mobx)) { return target } const adm = new ObservableObjectAdministration( target, new Map(), "ObservableObject", getAnnotationFromOptions(options) ) addHiddenProp(target, $mobx, adm) return target }Copy the code

ExtendObservable associates this target with the OBJ object we passed in.

export function extendObservable<A extends Object, B extends Object>( target: A, properties: B, annotations? : AnnotationsMap<B, never>, options? : CreateObservableOptions ): A & B { const descriptors = getOwnPropertyDescriptors(properties) const adm: ObservableObjectAdministration = asObservableObject(target, options)[$mobx] startBatch() try { ownKeys(descriptors).forEach(key => { adm.extend_( key, descriptor[key as any],true) }) } finally { endBatch() } return target as any }Copy the code

extendObservableWill pass us inobjObject’s key and corresponding descriptor, passObservableObjectAdministrationThe instanceadmtheextend_Method, added to target.

To be continued

By this point, the Observable method is all sorted out, but we don’t get a glimpse of Mobx’s underlying principles. And we also met a strange object ObservableObjectAdministration. Observable Manager, as the name suggests, is a key class in Mobx, and it is this class that will lift the veil from Mobx.

Listen to the breakdown next time.