【问题标题】:Compare two deep nested object of objects and return only the differences in javascript / lodash比较对象的两个深层嵌套对象并仅返回 javascript / lodash 中的差异
【发布时间】:2017-02-16 18:30:38
【问题描述】:

我有 2 个深层嵌套对象。一个是“基础”对象,另一个是修改后的对象。

我本质上想从修改后的对象中“删除”基础对象并返回一个只包含不同数据的对象。这是一个例子:

基础对象:

baseObj : {
    image: {
        width: '100%',
        paddingTop: '0px',
        paddingRight: '0px',
        paddingBottom: '0px',
        paddingLeft: '0px'
    },
    wrap: {
        marginTop: '0px',
        marginRight: '0px',
        marginBottom: '0px',
        marginLeft: '0px'
    }
}

具有修改数据的对象

mergedObject : {
    image: {
        width: '100%',  
        paddingTop: '0px',
        paddingRight: '24px', // modified value
        paddingBottom: '24px', // modified value
        paddingLeft: '0px'
    },
    wrap: {
        height: '100px', // new value
        marginTop: '24px', // modified value
        marginRight: '0px',
        marginBottom: '0px',
        marginLeft: '24px' // modified value
    }
}

我想要一个像这样返回的对象:

diffObject : {
    image: {
        paddingRight: '24px',
        paddingBottom: '24px',
    },
    wrap: {
        height: '100px',
        marginTop: '24px',
        marginLeft: '24px'
    }
}

嵌套可以更深一些,所以它需要是动态的。有没有使用 lodash 或其他库的方法?

【问题讨论】:

  • 谢谢。我在该页面上找到了一个 jsfiddle:jsfiddle.net/drzaus/9g5qoxwj 它几乎可以满足我的需求。但是它返回空对象,例如: "diff(a, b) = " {"x":4,"z":{},"zz":{"a":1,"b":2}} "diff(a, b) = " {"x":56,"z":{},"zz":{"a":2,"b":1}}。如果我能找到删除 z:{} 值的方法,那就完美了

标签: javascript node.js lodash javascript-objects


【解决方案1】:

要解决这个问题,我们必须:

  • 创建一个递归遍历对象中每个节点的函数。我们可以通过在遍历source对象时使用reduce函数来实现。
  • reduce 回调函数将首先检查source 值或其other 值计数器部分是否都是对象。如果是,我们将使用这些值作为参数以递归方式获取这两个对象的差异。否则,如果它们不同,那么我们将从 other 值分配结果值。
  • 最后,reduce 函数接受第三个参数,该参数用作reduce 函数累加的初始值。我们为第三个参数分配来自other 对象的键值对,这些键值在source 对象中找不到。这是从 other 对象向结果对象获取新引入的值的最简单方法。

function differenceObjectDeep(source, other) {
  return _.reduce(source, function(result, value, key) {
    if (_.isObject(value) && _.isObject(other[key])) {
      result[key] = differenceObjectDeep(
        value,
        other[key]
      );
    } else if (!_.isEqual(value, other[key])) {
      result[key] = other[key];
    }
    return result;
  }, _.omit(other, _.keys(source)));
}

data.diffObject = differenceObjectDeep(
  data.baseObj,
  data.mergedObject
);

var data = {
  baseObj: {
    image: {
      width: '100%',
      paddingTop: '0px',
      paddingRight: '0px',
      paddingBottom: '0px',
      paddingLeft: '0px'
    },
    wrap: {
      marginTop: '0px',
      marginRight: '0px',
      marginBottom: '0px',
      marginLeft: '0px'
    }
  },
  mergedObject: {
    image: {
      width: '100%',
      paddingTop: '0px',
      paddingRight: '24px', // modified value
      paddingBottom: '24px', // modified value
      paddingLeft: '0px'
    },
    wrap: {
      height: '100px', // new value
      marginTop: '24px', // modified value
      marginRight: '0px',
      marginBottom: '0px',
      marginLeft: '24px' // modified value
    }
  }
};

function differenceObjectDeep(source, other) {
  return _.reduce(source, function(result, value, key) {
    if (_.isObject(value) && _.isObject(other[key])) {
      result[key] = differenceObjectDeep(
        value,
        other[key]
      );
    } else if (!_.isEqual(value, other[key])) {
      result[key] = other[key];
    }
    return result;
  }, _.omit(other, _.keys(source)));
}

data.diffObject = differenceObjectDeep(
  data.baseObj,
  data.mergedObject
);

console.log(data.diffObject);
body>div {
  min-height: 100%;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

【讨论】:

    【解决方案2】:

    你可以使用递归函数找到最后一个对象。

    var checkIfObject = function(item){ //recursive function
    _.each(item, function(v, k){
    if(_.isObject(v)){
    previousObject = k;
    previousResult = v;
    return checkIfObject(v);
    }else{
        finalChildObjects[previousObject] = previousResult;
    }
    })
    return finalChildObjects
    }
    
    /*Initialize Values for recursive function*/
    var finalChildObjects = {};
    var previousObject = '';
    var previousResult = '';
    baseObjectFinalTurn = checkIfObject(baseObj);
    /*Initialize Values for recursive function*/
    var finalChildObjects = {};
    var previousObject = '';
    var previousResult = '';
    mergedObjectFinalTurn = checkIfObject(mergedObject);
    console.clear();
    
    
    var difference = {};
    _.each(baseObjectFinalTurn, function(v, k){
        if(mergedObjectFinalTurn[k]){
        difference[k] = _.reduce(mergedObjectFinalTurn[k],function(result, value, key){
        if(baseObjectFinalTurn[k][key] != mergedObjectFinalTurn[k][key]){
        result[key] =  value;
        }
        
        return result
        }, {})
        
      }
      else{
      difference[k] = {};
      }
    })
    
    console.log(difference)
    

    你可以从这个jsfiddle link验证结果

    注意:您需要根据您在reduce中的要求调整结果。此结果与您的输出相匹配。

    【讨论】:

    • 感谢您的意见。我运行了小提琴,我在控制台中看到的只是一个返回 true 或 false 的对象。我需要它是实际的不同数据
    • 抱歉,忘记更新小提琴了。感谢小提琴提供本地草稿。这是更新的代码jsfiddle.net/yx4ck723/4
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    • 2020-04-02
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-04
    相关资源
    最近更新 更多