在Git 找到Mobx 的源码, 发现其是使用TypeScript 编写,由于我对Typescrit 没有项目经验,因此我先会将其编译成JavaScript,因此咱们能够运行以下脚本或者从CDN直接下载一份编译过的源码,咱们能够选择umd 规范脚本:html
git clone git@github.com:mobxjs/mobx.git
npm i
npm run quick-build
首先咱们从一个最基本的Demo开始,来看Mobx 的基本使用方式:github
const addBtn = document.getElementById('add')
const minusBtn = document.getElementById('minus')
const incomeLabel = document.getElementById('incomeLabel')
const bankUser = mobx.observable({
name: 'Ivan Fan',
income: 3,
debit: 2
});
const incomeDisposer = mobx.autorun(() => {
incomeLabel.innerText = `Ivan Fan income is ${bankUser.income}`
})
addBtn.addEventListener('click', ()=> {
bankUser.income ++
})
minusBtn.addEventListener('click', () => {
bankUser.income --
})
复制代码复制代码
咱们的界面很是简单,如图: ajax
从上面的JS文件中,咱们发现其中引用了mobx 两个方法,分别是npm
和 autorun,是的,是这样两个方法,让 incomeLabel 在点击按钮的时候实时的发生了变化,因此咱们接下来会对这两个方法进行深刻分析,这一章节咱们会先分析Ctrl + K
Ctrl + 0
将代码都折叠起来, 而后在打开, 找到
exports 的代码块,咱们能够查看mobx 都暴露出了哪些方法:
observable,翻译成中文就是能够观测的, 咱们如今来调试这个方法, 咱们能够const bankUser = mobx.observable({
这一行打一个断点,而后F11
,跳进去,发现源码对应的是一个bash
var observable$$1 = createObservable;
function createObservable(v, arg2, arg3) {
if (typeof arguments[1] === "string") {
return deepDecorator$$1.apply(null, arguments);
}
if (isObservable$$1(v))
return v;
var res = isPlainObject$$1(v)
? observable$$1.object(v, arg2, arg3)
: Array.isArray(v)
? observable$$1.array(v, arg2)
: isES6Map$$1(v)
? observable$$1.map(v, arg2)
: v;
if (res !== v)
return res;
// otherwise, just box it
fail$$1(process.env.NODE_ENV !== "production" &&
"The provided value could not be converted into an observable. If you want just create an observable reference to the object use 'observable.box(value)'");
}
复制代码复制代码
上面代码很简单,参数有三个,可是咱们在调用的时候,值传递了一个参数, 因此咱们暂且只要关心第一个参数app
observable$$1.object
, observable$$1.array
, observable$$1.map
方法, 那这个observable$$1又是什么呢?在第一行var observable$$1 = createObservable;
表面就是createObservable方法。可是这个方法就短短几行代码,并无object, array, map着三个方法, 咱们发如今这个方法下面有observableFactories 对象,其是一个工厂对象,用来给createObservable添加方法,其定义了这三个方法,而且通遍历过Object.keys(observableFactories).forEach(function (name) { return (observable$$1[name] = observableFactories[name]); });
由于在咱们的Demo 中咱们传递的是一个Object, 因此会调用observable$$1.object
方法,接下来咱们在继续分析这个方法, 其代码以下:ide
object: function (props, decorators, options) {
if (typeof arguments[1] === "string")
incorrectlyUsedAsDecorator("object");
var o = asCreateObservableOptions$$1(options);
if (o.proxy === false) {
return extendObservable$$1({}, props, decorators, o);
}
else {
var defaultDecorator = getDefaultDecoratorFromObjectOptions$$1(o);
var base = extendObservable$$1({}, undefined, undefined, o);
var proxy = createDynamicObservableObject$$1(base);
extendObservableObjectWithProperties$$1(proxy, props, decorators, defaultDecorator);
return proxy;
}
},
复制代码复制代码
var o = asCreateObservableOptions$$1(options);
生成的了一个简单的对象:ui
var defaultCreateObservableOptions$$1 = {
deep: true,
name: undefined,
defaultDecorator: undefined,
proxy: true
};
复制代码复制代码
o.proxy
的值为true
, 因此会走else
逻辑分支, 因此接下来咱们一一分析else
分支中的每一条代码。spa
var defaultDecorator = getDefaultDecoratorFromObjectOptions$$1(o);
这个是跟装饰器有关的逻辑,咱们先跳过var base = extendObservable$$1({}, undefined, undefined, o);
对
Symbol
数据类型。这一步操做很是重要,给一个空对象添加了一个
$mobx$$1
(var $mobx$$1 = Symbol("mobx administration");
)的属性, 其值是一个ObservableObjectAdministration
类型对象,其write
方法在后续数据拦截中会调用。
var proxy = createDynamicObservableObject$$1(base);
这个方法,最为核心, 对这个对象进行了代理(
对这个对象的属性的get
, set
, has
, deleteProperty
, ownKeys
, preventExtensions
方法进行了代理拦截,这个是Mobx 事件数据添加的一个核心点。
第三点的proxy
其实只是初始化了一个简单的代理对象,可是没有与咱们须要观察的target
(也就是mobx.observable
方法传递进来的须要被观察的对象)关联起来, extendObservableObjectWithProperties$$1(proxy, props, decorators, defaultDecorator);
方法会遍历target
的属性,将其赋值给proxy
对象, 而后咱们mobx.observable
里的对象都被代理了,也就是实现了对属性操做的拦截处理。
在第四点extendObservableObjectWithProperties$$1
方法中, 最终会给原始的对象的属性进行装饰,经过查看function 的 call stack 得知,最后对调用
从图三中发现, 真正实现数据拦截的就是objectProxyTraps
拦截器, 下一章节,咱们须要对这个拦截器进行深刻分析,着重看get
,set
如何实现了数据拦截。
return proxy;
最终将返回一个已经被代理过的对象,替换原生对象。bankUser 对象就是一个已经被代理了的对象,而且包含了一个
Symbol
类型的新的属性。
const bankUser = mobx.observable({
name: 'Ivan Fan',
income: 3,
debit: 2
});
复制代码复制代码
array
, map
, object
, 如今只分析object 类型的状况)var base = extendObservable$$1({}, undefined, undefined, o);
), 包括一个Symbol
类型的属性,其值是一个ObservableObjectAdministration
类型的对象.get
, set
...) var proxy = new Proxy(base, objectProxyTraps);
bankUser