上篇文章Mobx 源码分析 - 热身提到,observable
上绑定了 13 个方法。此篇文章会重点讲解 shallowBox
和 box
。react
当调用 observable.shallowBox
时,mobx
会给出废弃警告,并帮你转换成 observable.box
,只是在转换的时候,会给 observable.box
传入第二个参数 { name, deep: false }
,这个参数的做用即是告诉 observable.box
在实例化 ObservableValue
时,使用 referenceEnhancer
。app
referenceEnhancer
禁用自动的 observable
转换,只是建立一个 observable
引用。函数
相反的,若是咱们调用 observable.box
,并给其传入 { deep: true }
。源码分析
能够看到,value
这时已是 ObservableValue
的实例。post
打开 types/observablevalue.ts
文件,该文件向外界暴露 ObservableValue
类和 isObservableValue
方法。ui
ObservableValue
类继承 Atom
类。ObservableValue
类的构造函数接收 5 个参数,分别为 value
、enhancer
、name
、notifySpy
和 equals
,其中 name
与 equals
存在默认值。name
没什么好说的,就是一个 id
,equals
的默认值为 comparer.default
,comparer.default
主要用来判断两个值是否相等。Atom
构造函数,并把 value
值设为传递进来的 enhancer
函数执行的结果。spy
数量,若是有,则发送一个事件。dehanceValue
、set
、prepareNewValue
、setNewValue
、get
、intercept
、observe
、toJSON
、toString
和 valueOf
。valueOf
方法。ObservableValue.prototype[primitiveSymbol()] = ObservableValue.prototype.valueOf
复制代码
ObservableValue
类 8 个公共方法,2 个私有方法。this
接收一个回调函数 listener
和是否当即调用 fireImmediately
。若是 fireImmediately
为 true
,则当即调用 listener
函数。spa
调用 registerListener
注册监听器,方法内部大部分与 registerInterceptor
实现相同。prototype
用来在任何变化应用前将其拦截。3d
方法内部调用 registerInterceptor
,registerInterceptor
函数内部会判断实例上是否存在 interceptors
,若是不存在,则赋为 []
,并把 handler
存入 interceptors
。最后返回一个函数,且该函数只能被调用一次。
export function registerInterceptor<T>( interceptable: IInterceptable<T>, handler: IInterceptor<T> ): Lambda {
...
return once(() => {
const idx = interceptors.indexOf(handler)
if (idx !== -1) interceptors.splice(idx, 1)
})
}
export function once(func: Lambda): Lambda {
let invoked = false
return function() {
if (invoked) return
invoked = true
return (func as any).apply(this, arguments)
}
}
复制代码
返回当前值,具体内容讲解会放在后面章节。
替换当前存储的值并通知全部观察者。
oldValue
,而后调用 prepareNewValue
方法生成新值 newValue
。newValue
是否等于 globalState.UNCHANGED
,若是等于什么都不作,若是不等于,则判断是否有监听器 spy
,有则发送 spyReportStart
事件,没有则什么都不作。setNewValue
方法spyReportEnd
事件返回 this.get()
reportChanged
函数,这里只了解大概,具体内容讲解会放在后面章节。listener
,若是有,调用 notifyListeners
方法public reportChanged() {
// 开始处理事务
startBatch();
// derivation、reaction
propagateChanged(this);
// 结束处理事务
endBatch();
}
复制代码
返回 ${this.name}[${this.value}]
返回 toPrimitive(this.get())
值得一提的是,方法内部会首先判断是否有拦截器 interceptor
。
若是有则会依次调用拦截器方法,并判断拦截器是否返回对象或 nothing,若是不是则报错;若是是 nothing,则直接返回,下面的拦截器再也不调用;若是是对象,则继续调用接下来的拦截器。
export function interceptChange<T>( interceptable: IInterceptable<T | null>, change: T | null ): T | null {
const prevU = untrackedStart()
try {
const interceptors = interceptable.interceptors
if (interceptors)
for (let i = 0, l = interceptors.length; i < l; i++) {
change = interceptors[i](change)
invariant(
!change || (change as any).type,
"Intercept handlers should return nothing or a change object"
)
if (!change) break
}
return change
} finally {
untrackedEnd(prevU)
}
}
复制代码
若是返回的 change
为 nothing,则直接返回 globalState.UNCHANGED
,不然取 change.newValue
做为新值。接下来方法和没有拦截器走的逻辑一致。
若是没有拦截器,则调用 enhancer
方法生成新值,最后判断旧值与新值是否相等,若是相等返回 globalState.UNCHANGED
,不然返回新值。
isObservableValue
函数是 createInstanceofPredicate
函数返回值。
var isObservableValue = createInstanceofPredicate("ObservableValue", ObservableValue);
复制代码
mox
源码阅读起来,很难理解,须要细细品尝。若是以为写得好不错,还请鼓励下,点个👍。