observable
同时支持 decorator
方式和方法调用方式。数组
// 示例
@observable name = '张三';
const temp = observable.box(20);
复制代码
在源码中能够发现 mobx
为 observable
上绑定了不少方法。缓存
Object.keys(observableFactories).forEach(function(name) {
return (observable[name] = observableFactories[name]);
});
复制代码
本篇文章重点介绍
@observable
调用,其他的后续文章会继续讲解。app
@observable
有一个很强大的功能,它会对于不一样类型,应用不一样的转换规则。它到底是如何处理的?函数
当咱们使用 @observable
,实质上是调用了 createObservable
的返回的 deepDecorator
函数。ui
createObservable
接收 3 个参数 v
、arg2
、arg3
,这三个参数分别对应构造函数的原型对象、属性名、描述符。this
function createObservable(v, arg2, arg3) {
// @observable someProp;
if (typeof arguments[1] === 'string') {
return deepDecorator.apply(null, arguments);
}
...
}
复制代码
deepDecorator
函数是 createDecoratorForEnhancer
的返回值,它把 deepEnhancer
做为参数传递进去。deepDecorator
的具体功能就是针对不一样类型使用不一样方式的 observable
。spa
var deepDecorator = createDecoratorForEnhancer(deepEnhancer);
复制代码
createDecoratorForEnhancer
函数会返回一个 res
,因此说当调用 @observable
时候就是等于执行 res
函数,传递进去的 deepEnhancer
会做为 res
的 enhancer
属性存在。code
createDecoratorForEnhancer
方法内部会经过 createPropDecorator
函数生成 res
。createPropDecorator
函数接收 2 个参数,第一个参数 propertyInitiallyEnumerable
设置为 true
( 内部写死 ),第二个参数 propertyCreator
为传递进来的函数。对象
createPropDecorator
函数返回 decoratorFactory
函数。看到这里,咱们先整理下,当咱们编写 @observable
,实质上就是在调用 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
函数内部会根据是否可枚举进行分类,并以属性名做为缓存对象的 key
,生成的描述符做为 value
存在。
尤为须要注意的是,描述符中有 get
和 set
方法,这两个方法内部都会首先调用 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
方法,传入 target
构造函数原型对象、propertyName
属性名、initialValue
初始值和 enhancer
( deepEnhancer
)。
function defineObservableProperty(target, propName, newValue, enhancer) {
var adm = asObservableObject(target);
}
复制代码
asObservableObject
方法会首先判断原型对象是否可扩展,若是不能够,则报错。其次根据必定规则生成 name
,经过调用 new ObservableObjectAdministration(target, name, defaultEnhancer)
生成 adm
对象,此对象会绑在原型对象的 $mobx
上,并返回新生成的 adm
对象。
defineObservableProperty
首先会经过调用 asObservableObject
方法获取 adm
对象,判断原型对象上的属性是否可配置与可写,若是不能够,报错。判断新生成的 adm
对象上是否存在 interceptors
属性,且属性值得长度大于 0
。
若是不存在,则给 adm
对象的 values
属性赋值,值为 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
方法最后会覆盖原型对象原有的属性描述符,并劫持 get
和 set
操做。
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);
}
}
}
复制代码
若是以为文章不错,对你有帮助,烦请点赞。