JavaScript:递归深度比较:对象和属性

2023-11-23

今天我读完了Ch. 4 在 Eloquent JS 中,我正在努力理解如何在对象及其属性之间执行深度比较,特别是通过使用递归调用。我知道我下面的解决方案非常幼稚而且有点笨重,但我正在努力理解我仍在学习的所有这些新事物!编程时间还不到一个月:) 如果您在改进代码方面可能有任何提示和帮助,并且如果您能帮助我更好地理解需要发生的递归,我将不胜感激。先感谢您!

  • 问题(Eloquent JS 第二版,第 4 章,练习 4):

编写一个函数 deepEqual,它接受两个值并返回 true 仅当它们具有相同的值或具有相同的对象时 与递归相比,其值也相等的属性 调用 deepEqual。


也许最简单的方法就是发布一个带有大量评论的函数来完成这项工作。递归部分位于传递给的函数的底部附近every:

// Helper to return a value's internal object [[Class]]
// That this returns [object Type] even for primitives
function getClass(obj) {
  return Object.prototype.toString.call(obj);
}

/*
** @param a, b        - values (Object, RegExp, Date, etc.)
** @returns {boolean} - true if a and b are the object or same primitive value or
**                      have the same properties with the same values
*/
function objectTester(a, b) {

  // If a and b reference the same value, return true
  if (a === b) return true;

  // If a and b aren't the same type, return false
  if (typeof a != typeof b) return false;

  // Already know types are the same, so if type is number
  // and both NaN, return true
  if (typeof a == 'number' && isNaN(a) && isNaN(b)) return true;

  // Get internal [[Class]]
  var aClass = getClass(a);
  var bClass = getClass(b)

  // Return false if not same class
  if (aClass != bClass) return false;

  // If they're Boolean, String or Number objects, check values
  if (aClass == '[object Boolean]' || aClass == '[object String]' || aClass == '[object Number]') {
    return a.valueOf() == b.valueOf();
  }

  // If they're RegExps, Dates or Error objects, check stringified values
  if (aClass == '[object RegExp]' || aClass == '[object Date]' || aClass == '[object Error]') {
    return a.toString() == b.toString();
  }

  // Otherwise they're Objects, Functions or Arrays or some kind of host object
  if (typeof a == 'object' || typeof a == 'function') {

    // For functions, check stringigied values are the same
    // Almost certainly false if a and b aren't trivial
    // and are different functions
    if (aClass == '[object Function]' && a.toString() != b.toString()) return false;

    var aKeys = Object.keys(a);
    var bKeys = Object.keys(b);

    // If they don't have the same number of keys, return false
    if (aKeys.length != bKeys.length) return false;

    // Check they have the same keys
    if (!aKeys.every(function(key){return b.hasOwnProperty(key)})) return false;

    // Check key values - uses ES5 Object.keys
    return aKeys.every(function(key){
      return objectTester(a[key], b[key])
    });
  }
  return false;
}

如果值/字符串不相同,则对 Date、RegExp、Error 等的测试可能应该返回 false,然后进行属性检查,但仅当您认为有人可能将属性附加到 Number 对象时才这样做(这是极其严重的)很少使用 Number 对象,更不用说向它们添加属性了,但我想这可能会发生)。

这里是:

/*
** @param a, b        - values (Object, RegExp, Date, etc.)
** @returns {boolean} - true if a and b are the object or same primitive value or
**                      have the same properties with the same values
*/
function objectTester(a, b) {

  // If a and b reference the same value, return true
  if (a === b) return true;

  // If a and b aren't the same type, return false
  if (typeof a != typeof b) return false;

  // Already know types are the same, so if type is number
  // and both NaN, return true
  if (typeof a == 'number' && isNaN(a) && isNaN(b)) return true;

  // Get internal [[Class]]
  var aClass = getClass(a);
  var bClass = getClass(b)

  // Return false if not same class
  if (aClass != bClass) return false;

  // If they're Boolean, String or Number objects, check values
  if (aClass == '[object Boolean]' || aClass == '[object String]' || aClass == '[object Number]') {
    if (a.valueOf() != b.valueOf()) return false;
  }

  // If they're RegExps, Dates or Error objects, check stringified values
  if (aClass == '[object RegExp]' || aClass == '[object Date]' || aClass == '[object Error]') {
    if (a.toString() != b.toString()) return false;
  }

  // For functions, check stringigied values are the same
  // Almost impossible to be equal if a and b aren't trivial
  // and are different functions
  if (aClass == '[object Function]' && a.toString() != b.toString()) return false;

  // For all objects, (including Objects, Functions, Arrays and host objects),
  // check the properties
  var aKeys = Object.keys(a);
  var bKeys = Object.keys(b);

  // If they don't have the same number of keys, return false
  if (aKeys.length != bKeys.length) return false;

  // Check they have the same keys
  if (!aKeys.every(function(key){return b.hasOwnProperty(key)})) return false;

  // Check key values - uses ES5 Object.keys
  return aKeys.every(function(key){
    return objectTester(a[key], b[key])
  });
  return false;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript:递归深度比较:对象和属性 的相关文章