本文翻译自https://www.chakshunyu.com/blog/how-does-shallow-comparison-work-in-react/

浅比较这个概念在React开发过程中很常见。它在不同的过程中扮演着关键的角色,也可以在React组件生命周期的几个地方找到。判断class组件是否应该更新、React hood的依赖数组、通React.memo 缓存处理等例子

如果曾经阅读过官方的React文档,我们可能会经常到看到浅比较这个概念。但通常只是一个比较简单的解释。所以,本文将研究浅比较的概念,它到底是什么、如何工作,并会得到一些我们可能不知道的结论

深入浅比较的实现

最直接了解浅比较的方式就是去深入它的实现。相应的代码可以在React Github项目的shared包中的shallowEqual.js找到。代码如下

import is from './objectIs';
import hasOwnProperty from './hasOwnProperty';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;
}

这个函数做了不少事情,我们一步一步看这个函数

function shallowEqual(objA: mixed, objB: mixed): boolean {// ...
}

函数接收两个入参作为被比较的对象。这个代码使用了Flow作为类型检测系统而不是使用TypeScript。两个函数的参数都使用了Flow中的mixed类型(类似TypeScript中的unknnown)。这表明它们可以是任意类型。

import is from './objectIs';function shallowEqual(objA: mixed, objB: mixed): boolean {if (is(objA, objB)) {return true;}// ...
}

首先使用React的内部实现的is方法对两个函数参数进行比较。这个引入的is内部方法和js中的Object.js几乎没有区别。这个比较函数和常用的===基本相同,除了两个例外

  • Object.is+0-0当作不相等,而===把他们当作相等
  • Object.isNumber.NaNNumber.NaN当作相等,而===把他们当作不相等

基本上第一个条件分支能处理如下简单的情况:如果两个参数有相同的值,如原始值相等、或对象的引用相等,它们会被认为相等

function shallowEqual(objA: mixed, objB: mixed): boolean {// ...if (typeof objA !== 'object' ||objA === null ||typeof objB !== 'object' ||objB === null) {return false;}// ...
}

处理了简单情况下的值相等或者对象引用相等后我们需要去比较更复杂的结构。如果其中一个参数是原始值,前面的比较仍然会漏掉这种情况

为了确保我们下面是比较两个复杂的数据结构,我们还需要检查是否其中一个参数不是对象或者是null。前一个检查确保我们处理的两个参数是对象或数组,而后一个检查是过滤掉null,因为的typeof null === 'object'。如果两个条件都成立那么处理的两个参数肯定是不相等的(否则前面的判断就会将它们过滤),所以浅比较返回false。

function shallowEqual(objA: mixed, objB: mixed): boolean {// ...const keysA = Object.keys(objA);const keysB = Object.keys(objB);if (keysA.length !== keysB.length) {return false;}// ...
}

现在可以确定我们只处理数组和对象。因此可以把重点放在复杂数据结构的比较上

首先,我们可以简单比较它们的键的数量是否相等。如果不是,他们就不会浅比较相等,这可以提高检查的效率。我们使用Object.keys获取它们的键的数量。对于对象,键数组由实际的键组成;而对于数组,键数组将由数组的索引组成。

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;
}

最后,我们遍历两个函数参数的值并逐个比较它们是否相等。使用上一步中生成的键数组,并使用hasOwnProperty检查键是否实际上是对象自身的属性,使用Object.is函数进行值比较

如果存在对象上的某个值不相等,那么通过浅比较就可以认为它们不相等。因此可以提前结束循环,并直接shallow wEqual函数返回false。如果所有的值都是相等那么我们可以通过浅比较函数判断两个参数相等,函数返回true

有趣的东西

我们已经了解了简单的比较和它背后的实现,也可以从中知道到一些有趣的东西:

  • 浅比较并不是使用全等===,而是使用Object.is

  • 浅比较中,空对象和空数组会被认为相等

  • 浅比较中,一个以索引值作为键的对象和一个在相应各下标处具有相同值的数组相等。如{0:2,1:3}等于[2,3]

  • 由于使用Object.is而不是使用===+0-0在浅比较中是不相等的。并且NaNNaN也认为不相等。这也适用于复杂结构内部的比较

  • 虽然两个直接创建的对象(或数组)通过浅比较是相等的({}[]),但嵌套的数组、对象是不相等的。如{someKey:{}{someKey:[]}浅比较是不相等的)

React中的浅比较是如何工作的?相关推荐

  1. java扫码枪键盘_浅谈在react中如何实现扫码枪输入

    触发原理 原理就是监听键盘输入,比如扫一个为6970596130126的69条形码,用扫码枪扫一下会在光标位置依次输出: 6 9 7 0 5 9 6 1 3 0 2 6 但这不是完整的,所以需要写一个 ...

  2. Java防止Xss注入json_浅谈 React 中的 XSS 攻击

    作者:陈吉 转发链接:https://mp.weixin.qq.com/s/HweEFh78WXLawyQr_Vsl5g 前言 前端一般会面临 XSS 这样的安全风险,但随着 React 等现代前端框 ...

  3. react 中渲染html_如何在React中识别和解决浪费的渲染

    react 中渲染html by Nayeem Reza 通过Nayeem Reza 如何在React中识别和解决浪费的渲染 (How to identify and resolve wasted r ...

  4. 浅谈 git 底层工作原理

    浅谈 git 底层工作原理 系统复习到这里也快差不多了,大概就剩下两三个 sections,这里学习一下 git 的 hashing 和对象. 当然,跳过问题也不大. config 文件 这里还是会用 ...

  5. React中的Diff算法——Christopher Chedeau(原文翻译)

    React's diff algorithm是了解React中的Diff算法必读的文章之一,以下内容是我在阅读过程中边看边翻译的,非科班渣翻请谅解.强烈建议阅读英文原文. 原文地址: React's ...

  6. mobx在react中应用_借助React Native Elements,Jest和MobX MST可以轻松实现现实世界中的ReactNative应用...

    mobx在react中应用 by Qaiser Abbas 由Qaiser Abbas 借助React Native Elements,Jest和MobX MST可以轻松实现现实世界中的ReactNa ...

  7. react中使用构建缓存_如何在React中构建热图

    react中使用构建缓存 Heat maps are a great way of visualizing correlations among two data sets.  With colors ...

  8. react中纯函数_如何在纯React中创建电子邮件芯片

    react中纯函数 by Andreas Remdt 由Andreas Remdt 如何在纯React中创建电子邮件芯片 (How to create email chips in pure Reac ...

  9. webuploader 怎么在react中_React 项目性能分析及优化

    点击上方"前端技术砖家"关注 性能优化不是一个简单的事情,但在 95% 以上的 React 项目中,是不需要考虑的,按自己的想法奔放的使用就可以了. 我认为性能优化最好的时候是项目 ...

最新文章

  1. xhr请求python_python爬取boss直聘职位数据,并保存到本地
  2. vue-cli2.0创建项目步骤
  3. Internet:从区块链的底层技术思考互联网是如何构成的
  4. 【项目管理】不确定性绩效域管理
  5. c25---条件编译
  6. php5.5 sqlserver 2012,PHP连接SQLSERVER2012
  7. 【Protocol Buffer】Protocol Buffer入门教程(一):简介和安装
  8. ORA-39083: + ORA-00439: 未启用功能
  9. 不同长度数据项的排序
  10. 2014-07-28 使用Axure RP进行手机端BBS的原型设计
  11. 计算机网络技术专业发展现状,计算机网络技术的发展现状和前景
  12. java 接口的声明和实现 总结_java知识总结(三):函数式接口
  13. POJ 3683 Priest John's Busiest Day (算竞进阶习题)
  14. 最全面的理解 | 工业互联网的前世今生
  15. 事件声音和提示 注册表全攻略
  16. (七)视频背景移除/去背景/换背景/抠图/抠像代码示例:实时抠图、实时抠像、人像去背景、背景消除
  17. bzoj5369 [Pkusc2018]最大前缀和
  18. 滴滴的大数据可视化效果
  19. SEO知识:百度谷歌搜狗谷歌必应搜索引擎蜘蛛的特点
  20. 计算机组成原理之原码一位乘法过程

热门文章

  1. 笑忘书——记苏州午时与同窗用餐遇雨有感
  2. c语言实验报告中致谢词,实验报告致谢词范文.doc
  3. C++ Standard Library
  4. 包和 jar 文件的创建
  5. 7.opencv图像对称翻折image-Flip(cv2.flip)
  6. 重装VMare出错:用户在命令行上发出了EULAS_AGREED=1,表示不接受许可协议
  7. Ant编译Java项目-QuickStart
  8. 分布式系统可用性和可靠性的区别,可用性如何计算,以及如何做到高可用和高可靠
  9. SRILM文档分析之Prob.h
  10. 3、乐趣国学—“色难”