当咱们写
age = observable.box(12)
的时候,写@observable age = 12
的时候,写age = observable(12)
的时候,mobx
作了什么?不知道有多少人仔细研究过,没研究也没关系,这篇文章就是带你去了解,mobx
具体作了什么?api
observable
上绑定了许多属性,好比经常使用的 box
、map
和 array
。当咱们调用 observable.box
的时候,mobx
会首先判断当前调用方式,若是当前的调用方式会 decorator
调用,则直接报错。函数
if (arguments.length > 2) incorrectlyUsedAsDecorator("box")
复制代码
为何 mobx
能够经过参数个数就能判断出来当前是否为 decorator
调用?那是由于若是经过装饰器调用,会往函数内传入 3 个参数,因此这边经过判断参数个数就能够肯定当前是否为 decorator
调用。源码分析
相信你们都知道 box
方法还有第二个参数 (不单单只是 box
有),这个参数的做用主要用以判断用哪个 enhancer
和 name
的值。post
最后返回 ObservableValue
实例。ui
new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals)
复制代码
调用 observable
时候,等于调用 createObservable
。spa
const observable = createObservable
复制代码
createObservable
接收 3 个参数,内部会对第二个参数进行判断,若是为 string
,则调用 deepDecorator
函数。3d
若是传入的参数为已监听对象,则直接返回;若是不是基本数据类型,则根据参数类型调用不一样的包装方法,好比对于 array
调用 observable.array
。若是是 NaN
,直接返回。若是是基本数据类型,提醒用户使用 observable.box
方法。code
咱们已经知道 mobx
对于咱们的代码会作两件不一样的事,一种调用 deepDecorator
函数,一种实例化 ObservableValue
。对象
注意,这里咱们只针对于传入的值为
number
类型讨论,不一样类型有不一样的实现方式继承
实例化 ObservableValue
,ObservableValue
类继承 Atom
类,ObservableValue
内部重写了 set
和 get
方法。
当访问实例时,会向全局发出 reportObserved
事件,并把当前实例存到 derivation.newObserving
中,以便数据发生更改,通知 derivation
。在这里,实例为被观察者,derivation
为观察者。
修改实例值时,会开启事务处理,并向全部的观察者推送这次事件,推送完成后结束事务处理。
究竟 mobx
是如何更新依赖关系?咱们以 autorun
举例。
autorun(()=>{
console.log(age.get())
})
复制代码
当咱们调用 autorun
时候,会在全局状态中增长当前实例,也就是当前的 derivation
,autorun
参数执行时,会把 age
的值,也就是 ObservableValue
实例,推入到当前的 derivation
属性中,derivation
会用 diffValue
来刷新当前依赖关系,保持依赖最新。
调用 createDecoratorForEnhancer
返回值,在原型上添加 __mobxDecorators
对象,此对象的每个属性 ( 比方说 @observable age,这里面的属性就是 age ) 都会存放一些关键信息,并劫持属性的 get
与 set
方法。
target.__mobxDecorators[prop] = {
prop,
propertyCreator,
descriptor,
decoratorTarget: target,
decoratorArguments
}
复制代码
当访问属性,会在原型上添加 __mobxDidRunLazyInitializers
和 $mobx
。$mobx
内存放 ObservableObjectAdministration
实例,并在 $mobx.values
对应的每个属性存放 ObservableValue
实例。
const observable = (adm.values[propName] = new ObservableValue(
newValue,
enhancer,
`${adm.name}.${propName}`,
false
))
复制代码
并对于属性的访问和读取会再次劫持,每当访问,都会调用原型上 $mobx
中 read
和 write
方法。read
和 write
方法所作的事与 observable.box
内部 get
和 set
作的事情同样。