Skip to content

学习 react 的 shallowEqual  #24

Description

@devinxiang

源码:https://github.com/facebook/react/blob/master/packages/shared/shallowEqual.js
基础知识:

  1. Object.is

实现步骤:

  1. 通过 Object.is 判断基础数据类型和地址一样的对象,且处理掉 NaN 和 undefined 的情况;
  2. 排除输入值一个为对象的情况或 null 的情况;
  3. 比较两个对象属性长度
  4. 相等则循环比较对象属性的每个值是否存在且相同
const hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * inlined Object.is polyfill to avoid requiring consumers ship their own
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
 */
function is(x: any, y: any) {
  return (
    // 当 x === y 的时候,针对+0 不等于 -0的情况
    // 针对NaN的情况
    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
  );
}

/**
 * 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 {
  // 1. 首先对基础数据类型进行比较,或者两个对象具有同一个地址的情况
  // 判断两个值是否相等,对基本数据类型判断的很精确,当
  if (is(objA, objB)) {
    return true;
  }

  // 注意:is 对基本类型判断准确,但是如果不等,可能会出现一个是基础类型一个是对象这种对于后续浅比较漏判的情况。所以判断两个对象中有一个不是对象则可返回false,保证后续的对比都是 object
  // 2. 两个对比对象都必须是 object,且 object 不能为 null;
  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false;
  }
  
  // 3. 准备开始比较对象每个属性的值
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);
  // 4. 长度不等,肯定不相等
  if (keysA.length !== keysB.length) {
    return false;
  }

  // Test for A's keys different from B.
  // 5. 循环对比每个 key 的值
  for (let i = 0; i < keysA.length; i++) {
    if (
      !hasOwnProperty.call(objB, keysA[i]) ||
      !is(objA[keysA[i]], objB[keysA[i]])
    ) {
      return false;
    }
  }

  return true;
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions