摘要:此时为空对象当构造函数原型对象上存在属性,则执行下面代码。属性名传递进来的函数描述符构造函数原型对象此时为最后通过调用函数为属性生成描述符。初始值获取之后,调用方法,传入构造函数原型对象属性名初始值和。
observable 同时支持 decorator 方式和方法调用方式。
// 示例 @observable name = "张三"; const temp = observable.box(20);
在源码中可以发现 mobx 为 observable 上绑定了很多方法。
Object.keys(observableFactories).forEach(function(name) { return (observable[name] = observableFactories[name]); });
本篇文章重点介绍 @observable 调用,其余的后续文章会继续讲解。
@observable 有一个很强大的功能,它会对于不同类型,应用不同的转换规则。它究竟是如何处理的?
createObservable当我们使用 @observable,实质上是调用了 createObservable 的返回的 deepDecorator 函数。
createObservable 接收 3 个参数 v、arg2、arg3,这三个参数分别对应构造函数的原型对象、属性名、描述符。
function createObservable(v, arg2, arg3) { // @observable someProp; if (typeof arguments[1] === "string") { return deepDecorator.apply(null, arguments); } ... }createDecoratorForEnhancer
deepDecorator 函数是 createDecoratorForEnhancer 的返回值,它把 deepEnhancer 作为参数传递进去。deepDecorator 的具体功能就是针对不同类型使用不同方式的 observable。
var deepDecorator = createDecoratorForEnhancer(deepEnhancer);
createDecoratorForEnhancer 函数会返回一个 res,所以说当调用 @observable 时候就是等于执行 res 函数,传递进去的 deepEnhancer 会作为 res 的 enhancer 属性存在。
createPropDecoratorcreateDecoratorForEnhancer 方法内部会通过 createPropDecorator 函数生成 res。createPropDecorator 函数接收 2 个参数,第一个参数 propertyInitiallyEnumerable 设置为 true ( 内部写死 ),第二个参数 propertyCreator 为传递进来的函数。
createPropDecorator 函数返回 decoratorFactory 函数。看到这里,我们先整理下,当我们编写 @observable,实质上就是在调用 decoratorFactory 函数。
decoratorFactorydecoratorFactory 函数内部定义 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 函数为属性生成描述符。createPropertyInitializerDescriptor 函数内部会根据是否可枚举进行分类,并以属性名作为缓存对象的 key,生成的描述符作为 value 存在。
尤其需要注意的是,描述符中有 get 和 set 方法,这两个方法内部都会首先调用 initializeInstance 方法,然后才执行对应的数据操作。
initializeInstanceinitializeInstance 方法会首先判断原型对象是否 __mobxDidRunLazyInitializers 属性,如果存在,则后续都不执行。如果不存在,则会依次调用原型对象上 __mobxDecorators 属性对应的 propertyCreator 方法。
看到这里,可能有人就懵了,问 propertyCreator 方法哪来的?还记得我们在调用 createPropDecorator 函数传递进去的第二个参数吗?这个方法就是那来的。propertyCreator 内部首先会判断属性描述符中是否存在 get,这里的属性描述符是原有的属性描述符,而不是封装后的。如果存在 get 方法,则报错,否则继续执行。判断描述符是否存在,不存在则设置初始值为 undefined,存在则继续判断是否有 initializer 方法,如果没有,则初始值为描述符的 value。如果有此方法,否则执行此方法,获取属性初始值。
var initialValue = descriptor ? descriptor.initializer ? descriptor.initializer.call(target) : descriptor.value : undefined;defineObservableProperty
初始值获取之后,调用 defineObservableProperty 方法,传入 target 构造函数原型对象、propertyName 属性名、initialValue 初始值和 enhancer ( deepEnhancer )。
function defineObservableProperty(target, propName, newValue, enhancer) { var adm = asObservableObject(target); }asObservableObject
asObservableObject 方法会首先判断原型对象是否可扩展,如果不可以,则报错。其次根据一定规则生成 name,通过调用 new ObservableObjectAdministration(target, name, defaultEnhancer) 生成 adm 对象,此对象会绑在原型对象的 $mobx 上,并返回新生成的 adm 对象。
defineObservableProperty 首先会通过调用 asObservableObject 方法获取 adm 对象,判断原型对象上的属性是否可配置与可写,如果不可以,报错。判断新生成的 adm 对象上是否存在 interceptors 属性,且属性值得长度大于 0。
如果不存在,则给 adm 对象的 values 属性赋值,值为 ObservableValue 的实例。
ObservableValueObservableValue 类继承 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); } } }
如果觉得文章不错,对你有帮助,烦请点赞。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/106780.html
摘要:前言初衷以系列故事的方式展现源码逻辑,尽可能以易懂的方式讲解源码本系列文章用故事解读源码一用故事解读源码二用故事解读源码三用故事解读源码四装饰器和用故事解读源码五文章编排每篇文章分成两大段,第一大段以简单的侦探系列故事的形式讲解所涉及人物场 ================前言=================== 初衷:以系列故事的方式展现 MobX 源码逻辑,尽可能以易懂的方式...
摘要:所以这是一篇插队的文章,用于去理解中的装饰器和概念。因此,该的作用就是根据入参返回具体的描述符。其次局部来看,装饰器具体应用表达式是,其函数签名和是一模一样。等装饰器语法,是和直接使用是等效等价的。 ================前言=================== 初衷:以系列故事的方式展现 MobX 源码逻辑,尽可能以易懂的方式讲解源码; 本系列文章: 《【用故事解...
摘要:随后,执行官给出一张当张三存款发生变化之时,此机构的运作时序图的确,小机构靠人力运作,大机构才靠制度运转。第一条语句创建观察员第一条语句张三我们调用的时候,就创建了对象,对象的所有属性都将被拷贝至一个克隆对象并将克隆对象转变成可观察的。 ================前言=================== 初衷:网上已有很多关于 MobX 源码解读的文章,但大多阅读成本甚高。...
摘要:源码简记整体会写得比较乱,同时也比较简单,和读书笔记差不多,基本是边读边写。见谅主要三大部分的原子类,能够被观察和通知变化,继承于。同时里面有几个比较重要的属性与方法。 Mobx 源码简记 整体会写得比较乱,同时也比较简单,和读书笔记差不多,基本是边读边写。见谅~ 主要三大部分Atom、Observable、Derivation Atom Mobx的原子类,能够被观察和通知变化,obs...
摘要:原理分析的核心就是通过观察某一个变量,当该变量产生变化时,对应的内的回调函数就会发生变化。回调函数若依赖外部环境,则无法进行收集很好理解,的回调函数在预执行的时候无法到达那一行代码,所以收集不到。 Mobx解决的问题 传统React使用的数据管理库为Redux。Redux要解决的问题是统一数据流,数据流完全可控并可追踪。要实现该目标,便需要进行相关的约束。Redux由此引出了dispa...
阅读 998·2019-08-30 15:55
阅读 3439·2019-08-30 13:10
阅读 1267·2019-08-29 18:45
阅读 2346·2019-08-29 16:25
阅读 2106·2019-08-29 15:13
阅读 2421·2019-08-29 11:29
阅读 551·2019-08-26 17:34
阅读 1485·2019-08-26 13:57