我有2个不同的嵌套对象,我需要知道它们是否在其中一个嵌套属性中有不同。

var a = {};
var b = {};

a.prop1 = 2;
a.prop2 = { prop3: 2 };

b.prop1 = 2;
b.prop2 = { prop3: 3 };

对象可以更复杂,有更多嵌套的属性。但这是一个很好的例子。我可以选择使用递归函数或lodash的东西…


当前回答

如果你需要知道哪些属性是不同的,使用reduce():

_.reduce(a, function(result, value, key) {
    return _.isEqual(value, b[key]) ?
        result : result.concat(key);
}, []);
// → [ "prop2" ]

其他回答

这是我对这个问题的解决办法

const _ = require('lodash');

var objects = [{ 'x': 1, 'y': 2, 'z':3, a:{b:1, c:2, d:{n:0}}, p:[1, 2, 3]  }, { 'x': 2, 'y': 1, z:3, a:{b:2, c:2,d:{n:1}}, p:[1,3], m:3  }];

const diffFn=(a,b, path='')=>_.reduce(a, function(result, value, key) {

    if(_.isObjectLike(value)){
      if(_.isEqual(value, b[key])){
        return result;
      }else{

return result.concat(diffFn(value, b[key], path?(`${path}.${key}`):key))
      }
    }else{
return _.isEqual(value, b[key]) ?
        result : result.concat(path?(`${path}.${key}`):key);
    }
    
}, []);

const diffKeys1=diffFn(objects[0], objects[1])
const diffKeys2=diffFn(objects[1], objects[0])
const diffKeys=_.union(diffKeys1, diffKeys2)
const res={};

_.forEach(diffKeys, (key)=>_.assign(res, {[key]:{ old: _.get(objects[0], key), new:_.get(objects[1], key)} }))

res
/*
Returns
{
  x: { old: 1, new: 2 },
  y: { old: 2, new: 1 },
  'a.b': { old: 1, new: 2 },
  'a.d.n': { old: 0, new: 1 },
  'p.1': { old: 2, new: 3 },
  'p.2': { old: 3, new: undefined },
  m: { old: undefined, new: 3 }
}
*/

这是基于@JLavoie,使用lodash

let differences = function (newObj, oldObj) {
      return _.reduce(newObj, function (result, value, key) {
        if (!_.isEqual(value, oldObj[key])) {
          if (_.isArray(value)) {
            result[key] = []
            _.forEach(value, function (innerObjFrom1, index) {
              if (_.isNil(oldObj[key][index])) {
                result[key].push(innerObjFrom1)
              } else {
                let changes = differences(innerObjFrom1, oldObj[key][index])
                if (!_.isEmpty(changes)) {
                  result[key].push(changes)
                }
              }
            })
          } else if (_.isObject(value)) {
            result[key] = differences(value, oldObj[key])
          } else {
            result[key] = value
          }
        }
        return result
      }, {})
    }

https://jsfiddle.net/EmilianoBarboza/0g0sn3b9/8/

已经有很多答案发布,但对于那些好奇的人来说,避免编写任何代码来计算具有任何类型结构的两个对象之间的差异,实际上有一个库可以做到这一点。Lodash isEqual只返回true或false,它不返回任何关于更改属性的信息。https://www.npmjs.com/package/deep-diff

它返回两个对象之间差异的完整细节

import DeepDiff from 'deep-diff';
let a = {...} //some object
let b = {...} //some object 
var differences = DeepDiff.diff(a, b);

在这篇文章中也有人提出了类似的问题 获取2个JSON对象之间的差异

一个简单而优雅的解决方案是使用_。isEqual,它执行深度比较:

Var a = {}; Var b = {}; A.prop1 = 2; A.prop2 = {prop3: 2}; B.prop1 = 2; B.prop2 = {prop3: 3}; console.log(_。isEqual (a, b));//如果不同则返回false < script src = " https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js " > < /脚本>

然而,这个解决方案并没有显示哪个属性是不同的。

我需要知道它们的某个嵌套属性是否不同

其他答案为这个问题提供了可能令人满意的解决方案,但它非常困难和常见,似乎有一个非常受欢迎的包来帮助解决这个问题。

要使用这个包,你需要npm i deep-object-diff,然后:

const { diff } = require('deep-object-diff');
var a = {};
var b = {};

a.prop1 = 2;
a.prop2 = { prop3: 2 };

b.prop1 = 2;
b.prop2 = { prop3: 3 };

if (!_.isEqual(a, b)) {
  const abDiff = diff(a, b);
  console.log(abDiff);
  /*
  {
    prop2: {
      prop3: 3
    }
  }
  */
}

// or alternatively
const abDiff = diff(a, b);
if(!_.isEmpty(abDiff)) {
  // if a diff exists then they aren't deeply equal
  // perform needed actions with diff...
}

下面是一个更详细的案例,直接从他们的文档中删除属性:

const lhs = {
  foo: {
    bar: {
      a: ['a', 'b'],
      b: 2,
      c: ['x', 'y'],
      e: 100 // deleted
    }
  },
  buzz: 'world'
};

const rhs = {
  foo: {
    bar: {
      a: ['a'], // index 1 ('b')  deleted
      b: 2, // unchanged
      c: ['x', 'y', 'z'], // 'z' added
      d: 'Hello, world!' // added
    }
  },
  buzz: 'fizz' // updated
};

console.log(diff(lhs, rhs)); // =>
/*
{
  foo: {
    bar: {
      a: {
        '1': undefined
      },
      c: {
        '2': 'z'
      },
      d: 'Hello, world!',
      e: undefined
    }
  },
  buzz: 'fizz'
}
*/

有关实现细节和其他使用信息,请参阅该repo。