[email protected]原始碼解讀之基類ReactBaseClasses

語言: CN / TW / HK

「這是我參與11月更文挑戰的第23天,活動詳情檢視:2021最後一次更文挑戰

react對元件作了抽象,下面是react對元件的抽象。 js /** * Copyright (c) Facebook * This source code is licensed under the MIT */ 可以看到,版權屬於Facebook。採用MIT許可證。MIT許可證的含義為編寫的軟體可以閉源,但必須宣告版權所屬,同時可以以自己的名字發行廣告。也就是說你可以使用它,並且還可以使用它編寫的程式碼獲取利潤,並且可以閉源自己的軟體程式碼。 js function Component(props, context, updater) { this.props = props; this.context = context; this.refs = emptyObject; this.updater = updater || ReactNoopUpdateQueue; }

new 運算子建立一個使用者定義的物件型別的例項或具有建構函式的內建物件的例項。(摘自MDN)

簡單說,new運算子會建立一個例項。傳送門

什麼是例項? 這裡我們用幾個句子,讓讀者更直觀地理解例項。 - 你們哥倆好像一個模子裡出來地。(你們有著相同的基因) - 用模具做出來的餅乾。(做餅乾的模具有相同的外形深度)

這裡react作者採用函式的形式構造了一個偽類。 Component建構函式接收三個引數: - props,元件屬性,也即jsx裡給標籤新增的屬性。 - context,上下文 - updater,更新器,用來檢視更新。

將Component首字母大寫,表示這是一個類(偽類)。這個基礎類的作用是幫助更新一個元件的狀態。

```js Component.prototype.setState = function(partialState, callback) { if ( typeof partialState !== 'object' && typeof partialState !== 'function' && partialState != null ) { throw new Error( 'setState(...): takes an object of state variables to update or a ' + 'function which returns an object of state variables.', ); }

this.updater.enqueueSetState(this, partialState, callback, 'setState'); }; ``` 隨後,react給這個偽類提供了一個setState方法,如果傳遞的部分狀態不是物件或者一個函式就會丟擲一個錯誤。這樣限制了這個方法的引數型別。

然後通過更新佇列代理變更狀態更新檢視的操作,因而,註釋說,setState方法不保證狀態更新的同步性。也就是說這個代理收到setState請求後,首先會將這個過程入隊,在一定的時機批量更新。

所謂佇列,就是先入先出,不過更新器會合並這一更新。我們可以給建構函式傳遞更新其,因而我們可以定製我們自己的更新策略。

js Component.prototype.forceUpdate = function(callback) { this.updater.enqueueForceUpdate(this, callback, 'forceUpdate'); }; 繼而react給Component這個偽類又添加了一個方法,也就是在原型物件上添加了一個屬性。 forceUpdate同樣也是藉助更新器代理做這件事。 在這裡,react相當於規定了兩個介面,我們要實現更新器,必須實現enqueueSetStateenqueueForceUpdate這兩個方法。 通過面向介面程式設計,我們可以不用考慮方法的具體實現,介面內部做了什麼修改,對呼叫者來說是一個黑盒子。這樣,我們可以不斷優化程式碼而不必擔心程式碼突然跑不起來。這就是約定的強大作用。不是有一種編碼方式,約定大於配置

js function ComponentDummy() {} ComponentDummy.prototype = Component.prototype; const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy()); pureComponentPrototype.constructor = PureComponent; Object.assign(pureComponentPrototype, Component.prototype); pureComponentPrototype.isPureReactComponent = true; 1. PureComponent的建構函式和Component的建構函式一摸一樣。 2. 這裡react聲明瞭一個偽類ComponentDummy,同時將其原型賦值為Component的原型,這樣,ComponentDummy就擁有了ComponentsetStateforceUpdate方法。這樣實現了繼承。 3. 然後將PureComponent的原型設定為ComponentDummy的例項。這樣Component原型上props,context,updater(這些屬性是例項屬性)的變更不會影響到PureComponent,每一個例項的props,context,updater都是獨立的,只受例項的影響,不會受到Component的影響。 4. 通過設定是否純元件,來變更元件比對狀態的策略,採用淺比對來提升效能。 5. 通過宣告一個pureComponentPrototype常量來為PureComponent的顯示原型的constructorisPureReactComponent屬性賦值。

Object.assign() 方法用於將所有可列舉屬性的值從一個或多個源物件分配到目標物件。它將返回目標物件。

這裡目標物件是pureComponentPrototype也就是PureComponent的顯式原型,這裡再次合併原型物件,react說是為了避免這些方法的一個額外的原型跳躍(jump),因為PureComponent的原型被設定為了ComponentDummy的例項,這樣繼承的原型方法會通過原型鏈查詢,造成一定的效能損失,通過呼叫Object.assign,避免了一層原型鏈查詢。beautiful!

感謝讀者的閱讀,這裡react通過原型構造偽類,實現繼承和複用,同時運用了避免原型跳躍等技巧提升效能,是很好的學習js原型和類繼承原理的素材。如果覺得對您有一定的啟發,歡迎點贊,動動小手手。