React中的浅比较

昨晚加班学习,听到组内其他师傅(Adispring)在讨论解决bug的办法,提到一句这是一个浅比较,所以xxxxx,第一次听浅比较,萌新感觉奇怪的知识又要增加了!

听说过深浅拷贝,所以看看浅比较是啥?

字面意思,猜测如同两个参数比较得不是很完全,比如=====的区别

在官方文档性能优化里有这么一说:

The problem is that PureComponent will do a simple comparison between the old and new values of this.props.words. Since this code mutates the words array in the handleClick method of WordAdder, the old and new values of this.props.words will compare as equal, even though the actual words in the array have changed. The ListOfWords will thus not update even though it has new words that should be rendered.

意思就是在确定是否重新渲染组件,是根据props和state的是否变化来判断,但判断它俩是否相同,只是简单比较了一下,如果是一些嵌套对象什么的就没办法准确比较

在React中有一个shouldComponentUpdate,用于根据state是否变化来判断是否需要更新(render)组件,如果state没有变化,那么就不重新渲染组件,否则渲染组件,有了这样一个判断逻辑,那么程序在运行的时候必然能减少一大部分多余的性能开销。

下图是官方给到的示例图:

更新比较

看看源码吧

const hasOwnProperty = Object.prototype.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 {
    // 调用Object.is判断是否相等,相同返回true,不同返回false
    if (Object.is(objA, objB)) {
      return true;
    }
    // object.is比较发现不等,但并不代表真的不等,object对象还需要比较
    // 这里判断是否是object,如果不是,那直接返回false
    if (
      typeof objA !== 'object' ||
      objA === null ||
      typeof objB !== 'object' ||
      objB === null
    ) {
      return false;
    }

    const keysA = Object.keys(objA);
    const keysB = Object.keys(objB);
    // 比较对象中的keys长度,不等返回false
    if (keysA.length !== keysB.length) {
      return false;
    }
    // 比较对象中相同的key的val是否相等
    for (let i = 0; i < keysA.length; i++) {
      if (
        !hasOwnProperty.call(objB, keysA[i]) ||                    // 判断在objB中是否有objA中的所有key,比较key是否相同
        !Object.is(objA[keysA[i]], objB[keysA[i]])            // 判断同key的value是否相同
      ) {
        return false;
      }
    }
    return true;
  }

    // 浅比较函数
    // 比较了props和nextProps,state和nextState
  function shallowCompare(instance, nextProps, nextState) {
    return (
      !shallowEqual(instance.props, nextProps) ||
      !shallowEqual(instance.state, nextState)
    );
  }
// Object.is
// 如果x === y相等时,返回x !== 0 || 1 / x === 1 / y
// 否则返回x !== x && y !== y
function is(x: any, y: any) {
  return (
    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
  );
}

/*
* 为什么要这么比较?可以参考下面的图
*/
// x === y 的时候,比较了类型和值
// 但,+0 === -0 ,结果为true,但我们希望结果应该是false
// NaN === NaN,结果为false,但我们希望结果应该是true
// 当 +0 === -0 进入判断体中,再比较x!==0,结果为false,+1/0 === -1/0 => Infinity === -Infinity,结果就为false
// 当不相等的时候,进入第二个判断体,此时NaN比较则返回了true,然后x与y做&&比较,返回结果

神奇的js

总结

通过如上分析,可以发现,在object比较的时候,Object.is()无法比较对象属性中嵌套对象是否相等,与此同时也没有判断顺序,例如某两个对象属性名交叉相同,而且值都是数值18,那么也会判断相同,但实际上他们在顺序上并不相同,可能经历过增删等操作,虽然结果一致,但并不是严谨的相等判断。

如果是一些复杂的对象比较,建议可以根据业务需求自行写判断逻辑。

Reference:

  1. https://zh-hans.reactjs.org/docs/optimizing-performance.html
  2. https://reactjs.org/docs/optimizing-performance.html
发表评论 / Comment

用心评论~


Warning: Cannot modify header information - headers already sent by (output started at /www/wwwroot/blog.dyboy.cn/content/templates/dyblog/footer.php:56) in /www/wwwroot/blog.dyboy.cn/include/lib/view.php on line 23