我有 2 个不同的嵌套对象,我需要知道它们的嵌套属性之一是否存在差异。
var a = {};
var b = {};
a.prop1 = 2;
a.prop2 = { prop3: 2 };
b.prop1 = 2;
b.prop2 = { prop3: 3 };
具有更多嵌套属性的对象可能会复杂得多。但这是一个很好的例子。我可以选择使用递归函数或 lodash 的东西......
我有 2 个不同的嵌套对象,我需要知道它们的嵌套属性之一是否存在差异。
var a = {};
var b = {};
a.prop1 = 2;
a.prop2 = { prop3: 2 };
b.prop1 = 2;
b.prop2 = { prop3: 3 };
具有更多嵌套属性的对象可能会复杂得多。但这是一个很好的例子。我可以选择使用递归函数或 lodash 的东西......
一个简单而优雅的解决方案是使用_.isEqual,它执行深度比较:
var a = {};
var b = {};
a.prop1 = 2;
a.prop2 = { prop3: 2 };
b.prop1 = 2;
b.prop2 = { prop3: 3 };
console.log(_.isEqual(a, b)); // returns false if different
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
但是,此解决方案并未显示哪个属性不同。
如果您需要知道哪些属性不同,请使用reduce():
_.reduce(a, function(result, value, key) {
    return _.isEqual(value, b[key]) ?
        result : result.concat(key);
}, []);
// → [ "prop2" ]
对于任何在此线程上绊倒的人,这里有一个更完整的解决方案。它将比较两个对象,并为您提供仅在 object1 中、仅在 object2中或同时在 object1 和 object2 中但具有不同值的所有属性的键:
/*
 * Compare two objects by reducing an array of keys in obj1, having the
 * keys in obj2 as the intial value of the result. Key points:
 *
 * - All keys of obj2 are initially in the result.
 *
 * - If the loop finds a key (from obj1, remember) not in obj2, it adds
 *   it to the result.
 *
 * - If the loop finds a key that are both in obj1 and obj2, it compares
 *   the value. If it's the same value, the key is removed from the result.
 */
function getObjectDiff(obj1, obj2) {
    const diff = Object.keys(obj1).reduce((result, key) => {
        if (!obj2.hasOwnProperty(key)) {
            result.push(key);
        } else if (_.isEqual(obj1[key], obj2[key])) {
            const resultKeyIndex = result.indexOf(key);
            result.splice(resultKeyIndex, 1);
        }
        return result;
    }, Object.keys(obj2));
    return diff;
}
这是一个示例输出:
// Test
let obj1 = {
    a: 1,
    b: 2,
    c: { foo: 1, bar: 2},
    d: { baz: 1, bat: 2 }
}
let obj2 = {
    b: 2, 
    c: { foo: 1, bar: 'monkey'}, 
    d: { baz: 1, bat: 2 }
    e: 1
}
getObjectDiff(obj1, obj2)
// ["c", "e", "a"]
如果你不关心嵌套对象并想跳过 lodash,你可以用 代替_.isEqual一个正常的值比较,例如obj1[key] === obj2[key].
根据Adam Boduch 的回答,我编写了这个函数,它在最深的意义上比较两个对象,返回具有不同值的路径以及一个或另一个对象缺少的路径。
编写代码时没有考虑到效率,在这方面的改进是最受欢迎的,但这里是基本形式:
var compare = function (a, b) {
  var result = {
    different: [],
    missing_from_first: [],
    missing_from_second: []
  };
  _.reduce(a, function (result, value, key) {
    if (b.hasOwnProperty(key)) {
      if (_.isEqual(value, b[key])) {
        return result;
      } else {
        if (typeof (a[key]) != typeof ({}) || typeof (b[key]) != typeof ({})) {
          //dead end.
          result.different.push(key);
          return result;
        } else {
          var deeper = compare(a[key], b[key]);
          result.different = result.different.concat(_.map(deeper.different, (sub_path) => {
            return key + "." + sub_path;
          }));
          result.missing_from_second = result.missing_from_second.concat(_.map(deeper.missing_from_second, (sub_path) => {
            return key + "." + sub_path;
          }));
          result.missing_from_first = result.missing_from_first.concat(_.map(deeper.missing_from_first, (sub_path) => {
            return key + "." + sub_path;
          }));
          return result;
        }
      }
    } else {
      result.missing_from_second.push(key);
      return result;
    }
  }, result);
  _.reduce(b, function (result, value, key) {
    if (a.hasOwnProperty(key)) {
      return result;
    } else {
      result.missing_from_first.push(key);
      return result;
    }
  }, result);
  return result;
}
您可以尝试使用此代码段的代码(建议在整页模式下运行):