You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
importisfrom'./objectIs';importhasOwnPropertyfrom'./hasOwnProperty';functionshallowEqual(objA: mixed,objB: mixed): boolean{if(is(objA,objB)){returntrue;}if(typeofobjA!=='object'||objA===null||typeofobjB!=='object'||objB===null){returnfalse;}constkeysA=Object.keys(objA);constkeysB=Object.keys(objB);if(keysA.length!==keysB.length){returnfalse;}// Test for A's keys different from B.for(leti=0;i<keysA.length;i++){constcurrentKey=keysA[i];if(!hasOwnProperty.call(objB,currentKey)||!is(objA[currentKey],objB[currentKey])){returnfalse;}}returntrue;}
importhasOwnPropertyfrom'./hasOwnProperty';functionshallowEqual(objA: mixed,objB: mixed): boolean{// ...// Test for A's keys different from B.for(leti=0;i<keysA.length;i++){constcurrentKey=keysA[i];if(!hasOwnProperty.call(objB,currentKey)||!is(objA[currentKey],objB[currentKey])){returnfalse;}}returntrue;}
浅比较这个概念在React开发过程中很常见。它在不同的过程中扮演着关键的角色,也可以在React组件生命周期的几个地方找到。判断class组件是否应该更新、React hood的依赖数组、通
React.memo
缓存处理等例子如果曾经阅读过官方的React文档,我们可能会经常到看到浅比较这个概念。但通常只是一个比较简单的解释。所以,本文将研究浅比较的概念,它到底是什么、如何工作,并会得到一些我们可能不知道的结论
深入浅比较的实现
最直接了解浅比较的方式就是去深入它的实现。相应的代码可以在React Github项目的
shared
包中的shallowEqual.js
找到。代码如下这个函数做了不少事情,我们一步一步看这个函数
函数接收两个入参作为被比较的对象。这个代码使用了
Flow
作为类型检测系统而不是使用TypeScript
。两个函数的参数都使用了Flow
中的mixed
类型(类似TypeScript
中的unknnown
)。这表明它们可以是任意类型。首先使用React的内部实现的
is
方法对两个函数参数进行比较。这个引入的is
内部方法和js中的Object.js
几乎没有区别。这个比较函数和常用的===
基本相同,除了两个例外Object.is
将+0
和-0
当作不相等,而===
把他们当作相等Object.is
把Number.NaN
和Number.NaN
当作相等,而===
把他们当作不相等基本上第一个条件分支能处理如下简单的情况:如果两个参数有相同的值,如原始值相等、或对象的引用相等,它们会被认为相等
处理了简单情况下的值相等或者对象引用相等后我们需要去比较更复杂的结构。如果其中一个参数是原始值,前面的比较仍然会漏掉这种情况
为了确保我们下面是比较两个复杂的数据结构,我们还需要检查是否其中一个参数不是对象或者是null。前一个检查确保我们处理的两个参数是对象或数组,而后一个检查是过滤掉
null
,因为的typeof null === 'object'
。如果两个条件都成立那么处理的两个参数肯定是不相等的(否则前面的判断就会将它们过滤),所以浅比较返回false。现在可以确定我们只处理数组和对象。因此可以把重点放在复杂数据结构的比较上
首先,我们可以简单比较它们的键的数量是否相等。如果不是,他们就不会浅比较相等,这可以提高检查的效率。我们使用
Object.keys
获取它们的键的数量。对于对象,键数组由实际的键组成;而对于数组,键数组将由数组的索引组成。最后,我们遍历两个函数参数的值并逐个比较它们是否相等。使用上一步中生成的键数组,并使用
hasOwnProperty
检查键是否实际上是对象自身的属性,使用Object.is
函数进行值比较如果存在对象上的某个值不相等,那么通过浅比较就可以认为它们不相等。因此可以提前结束循环,并直接
shallow wEqual
函数返回false。如果所有的值都是相等那么我们可以通过浅比较函数判断两个参数相等,函数返回true有趣的东西
我们已经了解了简单的比较和它背后的实现,也可以从中知道到一些有趣的东西:
浅比较并不是使用全等
===
,而是使用Object.is
浅比较中,空对象和空数组会被认为相等
浅比较中,一个以索引值作为键的对象和一个在相应各下标处具有相同值的数组相等。如
{0:2,1:3}
等于[2,3]
由于使用
Object.is
而不是使用===
。+0
和-0
在浅比较中是不相等的。并且NaN
和NaN
也认为不相等。这也适用于复杂结构内部的比较虽然两个直接创建的对象(或数组)通过浅比较是相等的(
{}
和[]
),但嵌套的数组、对象是不相等的。如{someKey:{}
和{someKey:[]}
浅比较是不相等的)The text was updated successfully, but these errors were encountered: