上篇文章简单介绍了observable部分的架构体系,并且分析了observableValue
这个类的结构。这篇文章将会继续分析observableObject
数据类型的源码,并且顺带讨论proxy
以及Object.defineProperty
两种实现方案。
observableObject
是如何实现的?
到这里我们已经可以回答observableArray
是如何实现的,通过Proxy
代理Array
的行为转发给ObservableArrayAdministration
实现响应式修改的逻辑。
同样我们也知道observableValue
是如何实现的,一个特殊的类ObservableValue
,直接使用这个类的方法甚至不需要代理。
而observableObject
的实现机制比较特殊,可以说它同时实现了上述两套方案,并在创建时决定使用哪一套方案。
让我们回到第一篇文章里提到的工厂。
const observableFactories: IObservableFactories = {
object<T = any>(
props: T,
decorators?: {
[K in keyof T]: Function },
options?: CreateObservableOptions
): T & IObservableObject {
if (typeof arguments[1] === "string") incorrectlyUsedAsDecorator("object")
const o = asCreateObservableOptions(options)
if (o.proxy === false) {
return extendObservable({}, props, decorators, o) as any
} else {
const defaultDecorator = getDefaultDecoratorFromObjectOptions(o)
const base = extendObservable({}, undefined, undefined, o) as any
const proxy = createDynamicObservableObject(base)
extendObservableObjectWithProperties(proxy, props, decorators, defaultDecorator)
return proxy
}
}
}
在例行公事的参数检查与options
格式化之后出现了分支。通过options.proxy
决定使用哪一套方案。
我们先看看proxy = false
时的第一种方案
第一条路:不用proxy
如何实现observableObject
这里直接返回了extendObservable
的结果。extendObservable
这个工具函数在mobx
的文档里也有提及。
ExtendObservable 用来向已存在的目标对象添加 observable 属性。 属性映射中的所有键值对都会导致目标上的新的 observable 属性被初始化为给定值。 属性映射中的任意 getters 都会转化成计算属性。
export function extendObservable<A extends Object, B extends Object>(
target: A,
properties?: B,
decorators?: {
[K in keyof B]?: Function },
options?: CreateObservableOptions
): A & B {
//...
const defaultDecorator = getDefaultDecoratorFromObjectOptions(options)
initializeInstance(target) // Fixes #1740
asObservableObject(target, options.name, defaultDecorator.enhancer) // make sure object is observable, even without initial props
if (properties)
extendObservableObjectWithProperties(target, properties, decorators, defaultDecorator)
return target as any
}
首先根据options
参数,选择特定的decorator
。这个过程是不是似曾相识。没错在之前的第一篇文章里我们也是通过options
参数去选择特定的enhancer
,这个enhancer
最终作用于每一个新加入数组的item
上。
实际上这里的decorator
也起着类似的作用,甚至创建decorator
这个过程本身也需要通过enhancer
这个参数 。
export const deepDecorator = createDecoratorForEnhancer(deepEnhancer)
const shallowDecorator = createDecoratorForEnhancer(shallowEnhancer)
export const refDecorator = createDecoratorForEnhancer(referenceEnhancer)
const refStructDecorator = createDecoratorForEnhancer(refStructEnhancer)
至于decorator
和enhancer
是如何耦合在一起的,实际上并不只是这个函数本身看起来这么简单 。