摘要:此時為空對象當構造函數原型對象上存在屬性,則執行下面代碼。屬性名傳遞進來的函數描述符構造函數原型對象此時為最后通過調用函數為屬性生成描述符。初始值獲取之后,調用方法,傳入構造函數原型對象屬性名初始值和。
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); } } }
如果覺得文章不錯,對你有幫助,煩請點贊。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106780.html
摘要:前言初衷以系列故事的方式展現源碼邏輯,盡可能以易懂的方式講解源碼本系列文章用故事解讀源碼一用故事解讀源碼二用故事解讀源碼三用故事解讀源碼四裝飾器和用故事解讀源碼五文章編排每篇文章分成兩大段,第一大段以簡單的偵探系列故事的形式講解所涉及人物場 ================前言=================== 初衷:以系列故事的方式展現 MobX 源碼邏輯,盡可能以易懂的方式...
摘要:所以這是一篇插隊的文章,用于去理解中的裝飾器和概念。因此,該的作用就是根據入參返回具體的描述符。其次局部來看,裝飾器具體應用表達式是,其函數簽名和是一模一樣。等裝飾器語法,是和直接使用是等效等價的。 ================前言=================== 初衷:以系列故事的方式展現 MobX 源碼邏輯,盡可能以易懂的方式講解源碼; 本系列文章: 《【用故事解...
摘要:隨后,執行官給出一張當張三存款發生變化之時,此機構的運作時序圖的確,小機構靠人力運作,大機構才靠制度運轉。第一條語句創建觀察員第一條語句張三我們調用的時候,就創建了對象,對象的所有屬性都將被拷貝至一個克隆對象并將克隆對象轉變成可觀察的。 ================前言=================== 初衷:網上已有很多關于 MobX 源碼解讀的文章,但大多閱讀成本甚高。...
摘要:源碼簡記整體會寫得比較亂,同時也比較簡單,和讀書筆記差不多,基本是邊讀邊寫。見諒主要三大部分的原子類,能夠被觀察和通知變化,繼承于。同時里面有幾個比較重要的屬性與方法。 Mobx 源碼簡記 整體會寫得比較亂,同時也比較簡單,和讀書筆記差不多,基本是邊讀邊寫。見諒~ 主要三大部分Atom、Observable、Derivation Atom Mobx的原子類,能夠被觀察和通知變化,obs...
摘要:原理分析的核心就是通過觀察某一個變量,當該變量產生變化時,對應的內的回調函數就會發生變化。回調函數若依賴外部環境,則無法進行收集很好理解,的回調函數在預執行的時候無法到達那一行代碼,所以收集不到。 Mobx解決的問題 傳統React使用的數據管理庫為Redux。Redux要解決的問題是統一數據流,數據流完全可控并可追蹤。要實現該目標,便需要進行相關的約束。Redux由此引出了dispa...
閱讀 1006·2019-08-30 15:55
閱讀 3446·2019-08-30 13:10
閱讀 1274·2019-08-29 18:45
閱讀 2352·2019-08-29 16:25
閱讀 2113·2019-08-29 15:13
閱讀 2427·2019-08-29 11:29
閱讀 559·2019-08-26 17:34
閱讀 1490·2019-08-26 13:57