網站首頁 編程語言 正文
React 中淺比較的概念無處不在,它在不同的流程中起著關鍵的作用,也可以在React組件的多個生命周期中找到。比如,React Hooks中的依賴數組,通過React.memo進行記憶。在React的官方文檔中也多次提到“淺比較”這個概念,下面我們就來看看React中的淺比較是如何工作的!
想要理解淺比較的概念,最直接的方法就是研究React的源代碼,下面就來看看React中的shallowEqual.js 文件:
import is from './objectIs';
import hasOwnProperty from './hasOwnProperty';
/**
?* Performs equality by iterating through keys on an object and returning false
?* when any key has values which are not strictly equal between the arguments.
?* Returns true when the values of all keys are strictly equal.
?*/
function shallowEqual(objA: mixed, objB: mixed): boolean {
? if (is(objA, objB)) {
? ? return true;
? }
? if (
? ? typeof objA !== 'object' ||
? ? objA === null ||
? ? typeof objB !== 'object' ||
? ? objB === null
? ) {
? ? return false;
? }
? const keysA = Object.keys(objA);
? const keysB = Object.keys(objB);
? if (keysA.length !== keysB.length) {
? ? return false;
? }
??
? // Test for A's keys different from B.
? for (let i = 0; i < keysA.length; i++) {
? ? const currentKey = keysA[i];
? ? if (
? ? ? !hasOwnProperty.call(objB, currentKey) ||
? ? ? !is(objA[currentKey], objB[currentKey])
? ? ) {
? ? ? return false;
? ? }
? }
? return true;
}
這里執行了很多步操作,下面就來將其拆分并逐步執行這些功能。先來看看函數的定義,這個函數接受兩個需要比較的對象,這里的代碼使用 Flow 作為類型檢查系統。兩個函數參數都是使用特殊的混合 Flow 類型定義,類似于 TypeScript 的 unknown,它表明函數可以是任何類型的值。
function shallowEqual(objA: mixed, objB: mixed): boolean {
// ...
}
之后使用 React 內部對象的 is 函數將兩個函數參數進行比較。導入的 is 函數只不過是JavaScript 的 Object.is 函數的polyfill 版本。 這個比較函數基本上等同于常見的 === 運算符,但有兩個例外:
- Object.is 認為 +0 和 -0 不相等,而 === 認為它們相等;
- Object.is 認為 Number.NaN 和 NaN 相等,而 === 認為它們不相等。
基本上,第一個條件語句可以處理所有簡單的情況:如果兩個函數參數具有相同的值,對于原始類型,或引用相同的對象(數組和對象),那么通過淺比較認為它們相等的。
import is from './objectIs';
function shallowEqual(objA: mixed, objB: mixed): boolean {
? if (is(objA, objB)) {
? ? return true;
? }
?? ?// ...
}
在處理兩個函數參數值相等或者引用同一個對象的所有簡單情況之后,來看看更復雜的結構:數組和對象。
為了確保現在要處理的是兩個復雜的結構,代碼會檢查任一參數是不是object類型或者等于null,前者用來確保我們處理的數組或對象,后者用來過濾掉空值,因為typeof null的結果也是 object。如果任何一個條件成立,那兩個參數一定是不相等的(否則前面的條件語句就會將它們過濾掉),因此淺比較直接返回false。
function shallowEqual(objA: mixed, objB: mixed): boolean {
?? ?// ...
? if (
? ? typeof objA !== 'object' ||
? ? objA === null ||
? ? typeof objB !== 'object' ||
? ? objB === null
? ) {
? ? return false;
? }
?? ?// ...
}
現在就可以確保我們處理的是數組和對象了,接下來我們深入研究復雜數據結構的值,并在兩個函數參數之間進行比較。在此之前,先來檢查兩個參數中值的數量是否相等,如果不相等,直接就可以確定兩個值是不相等的。對于對象,得到的keys數組就是由實際的key組成的;對于數組,得到keys數組數是由字符串類型的數組索引組成的。
function shallowEqual(objA: mixed, objB: mixed): boolean {
?? ?// ...
? const keysA = Object.keys(objA);
? const keysB = Object.keys(objB);
? if (keysA.length !== keysB.length) {
? ? return false;
? }
?? ?// ...
}
最后一步,按照 key 來迭代兩個函數參數的值,并逐個驗證他們是否是相等的。為此,代碼使用到了上一步中生成的keys數組,使用 hasOwnProperty 檢查key是否實際上是參數的屬性,并使用 Object.is 函數進行比較。
import hasOwnProperty from './hasOwnProperty';
function shallowEqual(objA: mixed, objB: mixed): boolean {
?? ?// ...
? // Test for A's keys different from B.
? for (let i = 0; i < keysA.length; i++) {
? ? const currentKey = keysA[i];
? ? if (
? ? ? !hasOwnProperty.call(objB, currentKey) ||
? ? ? !is(objA[currentKey], objB[currentKey])
? ? ) {
? ? ? return false;
? ? }
? }
? return true;
}
如果任何兩個key對應的值是不相等的,那兩個對象肯定就是不相等的,因此直接人會false,結束循環。如果所有的值都是相等的,就返回 true。
至此,我們通過 React 源碼學習了 React 中的淺比較,下面來總結一下其中有趣的知識吧:
- 淺比較使用的是 Object.is 函數,而不是使用嚴格相等 === 運算符;
- 通過淺比較,空對象和空數組是等價的;
- 通過淺比較,以數組索引為 key 和數組值為value的對象是等價的,比如:{ 0: 2, 1: 3 } 等價于 [2, 3];
- 由于通過Object.is比較的+0 和 -0、Number.NaN 和 NaN是不相等的,所以在復雜結構中比較時,這也是適用的;
- 雖然{} 和 [] 錢比較是相等的,但是嵌套在對象中對象是不相等的,比如:{ someKey: {} } 和 { someKey: [] } 是不相等的。
源碼:https://github.com/facebook/react/blob/main/packages/shared/shallowEqual.js
原文鏈接:https://juejin.cn/post/7090728097137295397
相關推薦
- 2022-04-04 Python?Opencv實現圖片切割處理_python
- 2023-05-30 docker如何查看容器啟動命令(已運行的容器)_docker
- 2022-07-18 SQL?Server中字符串函數的用法詳解_MsSql
- 2022-06-28 python神經網絡tfrecords文件的寫入讀取及內容解析_python
- 2022-11-26 詳解Python如何實現惰性導入-lazy?import_python
- 2022-05-18 Python?pandas?計算每行的增長率與累計增長率_python
- 2022-05-05 Android開發之自定義加載動畫詳解_Android
- 2022-07-19 詳解的wc find xargs zip gzip bzip2 xz tar sftp命令或者協議
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支