IT

두 객체 사이의 일반적인 깊은 차이

lottoking 2020. 5. 14. 08:17
반응형

두 객체 사이의 일반적인 깊은 차이


두 개의 객체가 있습니다 : oldObjnewObj.

의 데이터 oldObj는 양식을 채우는 데 사용되었으며 newObj사용자가이 양식의 데이터를 변경하여 제출 한 결과입니다.

두 물체 모두 깊습니다. 그들은 객체 또는 객체의 배열 등의 속성을 가지고 있습니다-n 레벨 깊이가 될 수 있으므로 diff 알고리즘은 재귀 적이어야합니다.

지금은 단지에서 (추가와 같이 / 업데이트 / 삭제) 변경이 있었는지 알아낼 필요 oldObjnewObj뿐만 아니라, 최선을 다해 그것을 표현하는 방법.

지금까지 내 생각은 genericDeepDiffBetweenObjects폼에 객체를 반환하는 메서드를 작성하는 {add:{...},upd:{...},del:{...}}것이지만 생각했습니다. 다른 사람이 전에 이것을 필요로 했어야합니다.

그래서 ... 누구든지 이것을 할 라이브러리 또는 코드 조각을 알고 있습니까 (아직 JSON 직렬화 가능한 방식으로) 차이를 나타내는 더 나은 방법이 있습니까?

최신 정보:

와 동일한 객체 구조를 사용 newObj하지만 모든 속성 값을 양식의 객체로 변환 하여 업데이트 된 데이터를 나타내는 더 좋은 방법을 생각했습니다 .

{type: '<update|create|delete>', data: <propertyValue>}

경우에 따라서 newObj.prop1 = 'new value'그리고 oldObj.prop1 = 'old value'그것을 설정합니다returnObj.prop1 = {type: 'update', data: 'new value'}

업데이트 2 :

배열 [1,2,3]이와 같은 수로 계산되어야하기 때문에 배열 인 속성에 도달하면 실제로 털이 발생 합니다 [2,3,1]. 이는 문자열, int 및 bool과 같은 값 기반 유형의 배열에 대해서는 간단하지만 처리 할 때 실제로 다루기가 어렵습니다 객체 및 배열과 같은 참조 유형의 배열.

동일해야하는 배열 예 :

[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]

이러한 유형의 깊은 가치 평등을 확인하는 것뿐만 아니라 변경 사항을 나타내는 좋은 방법을 찾는 것도 매우 복잡합니다.


나는 당신이 원하는 것을하고있는 작은 수업을 썼습니다 . 여기에서 테스트 할 수 있습니다 .

귀하의 제안과 다른 점은 [1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]동일한 것으로 간주하지 않는다는 것입니다. 요소의 순서가 같지 않으면 배열이 동일 하지 않다고 생각 하기 때문입니다. 물론 필요한 경우 변경할 수 있습니다. 또한이 코드는 전달 된 기본 값 (이 작업은 "compareValues"메소드에 의해 수행됨)에 따라 임의의 방식으로 diff 오브젝트를 형식화하는 데 사용되는 인수로 기능을 수행하도록 추가로 향상 될 수 있습니다.

var deepDiffMapper = function () {
  return {
    VALUE_CREATED: 'created',
    VALUE_UPDATED: 'updated',
    VALUE_DELETED: 'deleted',
    VALUE_UNCHANGED: 'unchanged',
    map: function(obj1, obj2) {
      if (this.isFunction(obj1) || this.isFunction(obj2)) {
        throw 'Invalid argument. Function given, object expected.';
      }
      if (this.isValue(obj1) || this.isValue(obj2)) {
        return {
          type: this.compareValues(obj1, obj2),
          data: obj1 === undefined ? obj2 : obj1
        };
      }

      var diff = {};
      for (var key in obj1) {
        if (this.isFunction(obj1[key])) {
          continue;
        }

        var value2 = undefined;
        if (obj2[key] !== undefined) {
          value2 = obj2[key];
        }

        diff[key] = this.map(obj1[key], value2);
      }
      for (var key in obj2) {
        if (this.isFunction(obj2[key]) || diff[key] !== undefined) {
          continue;
        }

        diff[key] = this.map(undefined, obj2[key]);
      }

      return diff;

    },
    compareValues: function (value1, value2) {
      if (value1 === value2) {
        return this.VALUE_UNCHANGED;
      }
      if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
        return this.VALUE_UNCHANGED;
      }
      if (value1 === undefined) {
        return this.VALUE_CREATED;
      }
      if (value2 === undefined) {
        return this.VALUE_DELETED;
      }
      return this.VALUE_UPDATED;
    },
    isFunction: function (x) {
      return Object.prototype.toString.call(x) === '[object Function]';
    },
    isArray: function (x) {
      return Object.prototype.toString.call(x) === '[object Array]';
    },
    isDate: function (x) {
      return Object.prototype.toString.call(x) === '[object Date]';
    },
    isObject: function (x) {
      return Object.prototype.toString.call(x) === '[object Object]';
    },
    isValue: function (x) {
      return !this.isObject(x) && !this.isArray(x);
    }
  }
}();


var result = deepDiffMapper.map({
  a: 'i am unchanged',
  b: 'i am deleted',
  e: {
    a: 1,
    b: false,
    c: null
  },
  f: [1, {
    a: 'same',
    b: [{
      a: 'same'
    }, {
      d: 'delete'
    }]
  }],
  g: new Date('2017.11.25')
}, {
  a: 'i am unchanged',
  c: 'i am created',
  e: {
    a: '1',
    b: '',
    d: 'created'
  },
  f: [{
    a: 'same',
    b: [{
      a: 'same'
    }, {
      c: 'create'
    }]
  }, 1],
  g: new Date('2017.11.25')
});
console.log(result);


밑줄을 사용하여 간단한 차이점 :

var o1 = {a: 1, b: 2, c: 2},
    o2 = {a: 2, b: 1, c: 2};

_.omit(o1, function(v,k) { return o2[k] === v; })

o1해당 부분 이 일치하지만 다음과 같은 값이 다릅니다 o2.

{a: 1, b: 2}

깊은 차이가 있으면 다릅니다.

function diff(a,b) {
    var r = {};
    _.each(a, function(v,k) {
        if(b[k] === v) return;
        // but what if it returns an empty object? still attach?
        r[k] = _.isObject(v)
                ? _.diff(v, b[k])
                : v
            ;
        });
    return r;
}

주석에서 @Juhana가 지적한 것처럼 위의 내용은 diff a-> b이며 되돌릴 수 없습니다 (b의 추가 속성은 무시 됨). 대신 a-> b-> a를 사용하십시오.

(function(_) {
  function deepDiff(a, b, r) {
    _.each(a, function(v, k) {
      // already checked this or equal...
      if (r.hasOwnProperty(k) || b[k] === v) return;
      // but what if it returns an empty object? still attach?
      r[k] = _.isObject(v) ? _.diff(v, b[k]) : v;
    });
  }

  /* the function */
  _.mixin({
    diff: function(a, b) {
      var r = {};
      deepDiff(a, b, r);
      deepDiff(b, a, r);
      return r;
    }
  });
})(_.noConflict());

전체 example + tests + mixins에 대해서는 http://jsfiddle.net/drzaus/9g5qoxwj/참조하십시오


ES6 솔루션을 제공하고 싶습니다 ... 단방향 차이입니다. 즉, 키와 값이 대응 o2하는 키 / 값을 반환합니다 o1.

let o1 = {
  one: 1,
  two: 2,
  three: 3
}

let o2 = {
  two: 2,
  three: 3,
  four: 4
}

let diff = Object.keys(o2).reduce((diff, key) => {
  if (o1[key] === o2[key]) return diff
  return {
    ...diff,
    [key]: o2[key]
  }
}, {})

Lodash 사용하기 :

_.mergeWith(oldObj, newObj, function (objectValue, sourceValue, key, object, source) {
    if ( !(_.isEqual(objectValue, sourceValue)) && (Object(objectValue) !== objectValue)) {
        console.log(key + "\n    Expected: " + sourceValue + "\n    Actual: " + objectValue);
    }
});

키 / 객체 / 소스를 사용하지 않지만 액세스 해야하는 경우 키를 남겨 두었습니다. 객체 비교는 콘솔이 가장 바깥 쪽 요소에서 가장 안쪽 요소까지 콘솔의 차이점을 인쇄하지 못하게합니다.

배열을 처리하기 위해 내부에 논리를 추가 할 수 있습니다. 아마도 배열을 먼저 정렬하십시오. 이것은 매우 유연한 솔루션입니다.

편집하다

lodash 업데이트로 인해 _.merge에서 _.mergeWith로 변경되었습니다. 변경 사항을 확인한 Aviron에게 감사합니다.


다음은 두 JavaScript 객체 사이의 차이점을 찾는 데 사용할 수있는 JavaScript 라이브러리입니다.

깃 허브 URL : https://github.com/cosmicanant/recursive-diff

Npmjs URL : https://www.npmjs.com/package/recursive-diff

재귀

브라우저와 Node.js에서 재귀 -diff 라이브러리를 사용할 수 있습니다. 브라우저의 경우 다음을 수행하십시오.

<script type="text" src="index.js"/>
<script type="text/javascript">
     var ob1 = {a:1, b: [2,3]};
     var ob2 = {a:2, b: [3,3,1]};
     var delta = diff.getDiff(ob1,ob2); 
     /* console.log(delta) will dump following data 
     {
         '/a':{operation:'update',value:2}
         '/b/0':{operation:'update',value:3},
         '/b/2':{operation:'add',value:1},
     } */
     var ob3 = diff.applyDiff(ob1, delta); //expect ob3 is deep equal to ob2
 </script>

node.js에서 'recursive-diff'모듈이 필요하고 아래처럼 사용할 수 있습니다.

var diff = require('recursive-diff');
var ob1 = {a: 1}, ob2: {b:2};
var diff = diff.getDiff(ob1, ob2);

요즘에는 사용할 수있는 모듈이 꽤 있습니다. 내가 찾은 수많은 diffing 모듈에 만족하지 않았기 때문에 최근 에이 작업을 수행하기 위해 모듈을 작성했습니다. 해당 호출 odiff: https://github.com/Tixit/odiff . 또한 가장 인기있는 모듈과 readme에서 허용되지 않는 이유를 나열했습니다 . 원하는 속성이없는 odiff경우 살펴볼 수 있습니다 odiff. 예를 들면 다음과 같습니다.

var a = [{a:1,b:2,c:3},              {x:1,y: 2, z:3},              {w:9,q:8,r:7}]
var b = [{a:1,b:2,c:3},{t:4,y:5,u:6},{x:1,y:'3',z:3},{t:9,y:9,u:9},{w:9,q:8,r:7}]

var diffs = odiff(a,b)

/* diffs now contains:
[{type: 'add', path:[], index: 2, vals: [{t:9,y:9,u:9}]},
 {type: 'set', path:[1,'y'], val: '3'},
 {type: 'add', path:[], index: 1, vals: [{t:4,y:5,u:6}]}
]
*/

설명하는 작업을 수행하기 위해이 코드를 사용했습니다.

function mergeRecursive(obj1, obj2) {
    for (var p in obj2) {
        try {
            if(obj2[p].constructor == Object) {
                obj1[p] = mergeRecursive(obj1[p], obj2[p]);
            }
            // Property in destination object set; update its value.
            else if (Ext.isArray(obj2[p])) {
                // obj1[p] = [];
                if (obj2[p].length < 1) {
                    obj1[p] = obj2[p];
                }
                else {
                    obj1[p] = mergeRecursive(obj1[p], obj2[p]);
                }

            }else{
                obj1[p] = obj2[p];
            }
        } catch (e) {
            // Property in destination object not set; create it and set its value.
            obj1[p] = obj2[p];
        }
    }
    return obj1;
}

그러면 기존 객체와 새 객체 간의 모든 변경 사항을 양식에서 병합하는 새 객체가 생성됩니다.


Javascript에서 "compareValue ()"라는 함수를 개발했습니다. 값이 같은지 여부를 반환합니다. 한 Object의 for 루프에서 compareValue ()를 호출했습니다. diffParams에서 두 객체의 차이를 얻을 수 있습니다.

var diffParams = {};
var obj1 = {"a":"1", "b":"2", "c":[{"key":"3"}]},
    obj2 = {"a":"1", "b":"66", "c":[{"key":"55"}]};

for( var p in obj1 ){
  if ( !compareValue(obj1[p], obj2[p]) ){
    diffParams[p] = obj1[p];
  }
}

function compareValue(val1, val2){
  var isSame = true;
  for ( var p in val1 ) {

    if (typeof(val1[p]) === "object"){
      var objectValue1 = val1[p],
          objectValue2 = val2[p];
      for( var value in objectValue1 ){
        isSame = compareValue(objectValue1[value], objectValue2[value]);
        if( isSame === false ){
          return false;
        }
      }
    }else{
      if(val1 !== val2){
        isSame = false;
      }
    }
  }
  return isSame;
}
console.log(diffParams);


나는 파티에 늦었다는 것을 알고 있지만 위의 답변이 도움이되지 않은 비슷한 것이 필요했습니다.

변수의 변화를 감지하기 위해 Angular의 $ watch 함수를 사용하고있었습니다. 변수에서 속성이 변경되었는지 여부를 알아야 할뿐만 아니라 변경된 속성이 계산 된 임시 필드가 아닌지 확인하고 싶었습니다. 즉, 특정 속성을 무시하고 싶었습니다.

코드는 다음과 같습니다. https://jsfiddle.net/rv01x6jo/

사용 방법은 다음과 같습니다.

// To only return the difference
var difference = diff(newValue, oldValue);  

// To exclude certain properties
var difference = diff(newValue, oldValue, [newValue.prop1, newValue.prop2, newValue.prop3]);

이것이 누군가를 돕기를 바랍니다.


나는 같은 문제를 해결하기 위해 람다를 사용한다. 새로운 객체에서 무엇이 바뀌 었는지 알아야한다. 여기 내 디자인이 있습니다.

const oldState = {id:'170',name:'Ivab',secondName:'Ivanov',weight:45};
const newState = {id:'170',name:'Ivanko',secondName:'Ivanov',age:29};

const keysObj1 = R.keys(newState)

const filterFunc = key => {
  const value = R.eqProps(key,oldState,newState)
  return {[key]:value}
}

const result = R.map(filterFunc, keysObj1)

결과는 속성 이름이며 상태입니다.

[{"id":true}, {"name":false}, {"secondName":true}, {"age":false}]

나는 이미 내 프로젝트 중 하나에 대해 사용자 옵션으로 객체를 내부 클론과 비교하는 함수를 작성했습니다. 또한 사용자가 순수한 자바 스크립트로 잘못된 유형의 데이터를 입력하거나 제거한 경우 기본값을 확인하고 기본값으로 바꿀 수도 있습니다.

IE8에서는 100 % 작동합니다. 성공적으로 테스트되었습니다.

//  ObjectKey: ["DataType, DefaultValue"]
reference = { 
    a : ["string", 'Defaul value for "a"'],
    b : ["number", 300],
    c : ["boolean", true],
    d : {
        da : ["boolean", true],
        db : ["string", 'Defaul value for "db"'],
        dc : {
            dca : ["number", 200],
            dcb : ["string", 'Default value for "dcb"'],
            dcc : ["number", 500],
            dcd : ["boolean", true]
      },
      dce : ["string", 'Default value for "dce"'],
    },
    e : ["number", 200],
    f : ["boolean", 0],
    g : ["", 'This is an internal extra parameter']
};

userOptions = { 
    a : 999, //Only string allowed
  //b : ["number", 400], //User missed this parameter
    c: "Hi", //Only lower case or case insitive in quotes true/false allowed.
    d : {
        da : false,
        db : "HelloWorld",
        dc : {
            dca : 10,
            dcb : "My String", //Space is not allowed for ID attr
            dcc: "3thString", //Should not start with numbers
            dcd : false
      },
      dce: "ANOTHER STRING",
    },
    e: 40,
    f: true,
};


function compare(ref, obj) {

    var validation = {
        number: function (defaultValue, userValue) {
          if(/^[0-9]+$/.test(userValue))
            return userValue;
          else return defaultValue;
        },
        string: function (defaultValue, userValue) {
          if(/^[a-z][a-z0-9-_.:]{1,51}[^-_.:]$/i.test(userValue)) //This Regex is validating HTML tag "ID" attributes
            return userValue;
          else return defaultValue;
        },
        boolean: function (defaultValue, userValue) {
          if (typeof userValue === 'boolean')
            return userValue;
          else return defaultValue;
        }
    };

    for (var key in ref)
        if (obj[key] && obj[key].constructor && obj[key].constructor === Object)
          ref[key] = compare(ref[key], obj[key]);
        else if(obj.hasOwnProperty(key))
          ref[key] = validation[ref[key][0]](ref[key][1], obj[key]); //or without validation on user enties => ref[key] = obj[key]
        else ref[key] = ref[key][1];
    return ref;
}

//console.log(
    alert(JSON.stringify( compare(reference, userOptions),null,2 ))
//);

/ * 결과

{
  "a": "Defaul value for \"a\"",
  "b": 300,
  "c": true,
  "d": {
    "da": false,
    "db": "Defaul value for \"db\"",
    "dc": {
      "dca": 10,
      "dcb": "Default value for \"dcb\"",
      "dcc": 500,
      "dcd": false
    },
    "dce": "Default value for \"dce\""
  },
  "e": 40,
  "f": true,
  "g": "This is an internal extra parameter"
}

*/

sbgoran의 답변에서보다 확장되고 단순화 된 기능.
이를 통해 심층 스캔이 가능하고 어레이의 유사성을 찾을 수 있습니다.

var result = objectDifference({
      a:'i am unchanged',
      b:'i am deleted',
      e: {a: 1,b:false, c: null},
      f: [1,{a: 'same',b:[{a:'same'},{d: 'delete'}]}],
      g: new Date('2017.11.25'),
      h: [1,2,3,4,5]
  },
  {
      a:'i am unchanged',
      c:'i am created',
      e: {a: '1', b: '', d:'created'},
      f: [{a: 'same',b:[{a:'same'},{c: 'create'}]},1],
      g: new Date('2017.11.25'),
      h: [4,5,6,7,8]
  });
console.log(result);

function objectDifference(obj1, obj2){
    if((dataType(obj1) !== 'array' && dataType(obj1) !== 'object') || (dataType(obj2) !== 'array' && dataType(obj2) !== 'object')){
        var type = '';

        if(obj1 === obj2 || (dataType(obj1) === 'date' && dataType(obj2) === 'date' && obj1.getTime() === obj2.getTime()))
            type = 'unchanged';
        else if(dataType(obj1) === 'undefined')
            type = 'created';
        if(dataType(obj2) === 'undefined')
            type = 'deleted';
        else if(type === '') type = 'updated';

        return {
            type: type,
            data:(obj1 === undefined) ? obj2 : obj1
        };
    }
  
    if(dataType(obj1) === 'array' && dataType(obj2) === 'array'){
        var diff = [];
        obj1.sort(); obj2.sort();
        for(var i = 0; i < obj2.length; i++){
            var type = obj1.indexOf(obj2[i]) === -1?'created':'unchanged';
            if(type === 'created' && (dataType(obj2[i]) === 'array' || dataType(obj2[i]) === 'object')){
                diff.push(
                    objectDifference(obj1[i], obj2[i])
                );
                continue;
            }
            diff.push({
                type: type,
                data: obj2[i]
            });
        }

        for(var i = 0; i < obj1.length; i++){
            if(obj2.indexOf(obj1[i]) !== -1 || dataType(obj1[i]) === 'array' || dataType(obj1[i]) === 'object')
                continue;
            diff.push({
                type: 'deleted',
                data: obj1[i]
            });
        }
    } else {
        var diff = {};
        var key = Object.keys(obj1);
        for(var i = 0; i < key.length; i++){
            var value2 = undefined;
            if(dataType(obj2[key[i]]) !== 'undefined')
                value2 = obj2[key[i]];

            diff[key[i]] = objectDifference(obj1[key[i]], value2);
        }

        var key = Object.keys(obj2);
        for(var i = 0; i < key.length; i++){
            if(dataType(diff[key[i]]) !== 'undefined')
                continue;

            diff[key[i]] = objectDifference(undefined, obj2[key[i]]);
        }
    }

    return diff;
}

function dataType(data){
    if(data === undefined || data === null) return 'undefined';
    if(data.constructor === String) return 'string';
    if(data.constructor === Array) return 'array';
    if(data.constructor === Object) return 'object';
    if(data.constructor === Number) return 'number';
    if(data.constructor === Boolean) return 'boolean';
    if(data.constructor === Function) return 'function';
    if(data.constructor === Date) return 'date';
    if(data.constructor === RegExp) return 'regex';
    return 'unknown';
}


@sbgoran 코드의 타입 스크립트 버전은 다음과 같습니다.

export class deepDiffMapper {

  static VALUE_CREATED = 'created';
  static VALUE_UPDATED = 'updated';
  static VALUE_DELETED = 'deleted';
  static VALUE_UNCHANGED ='unchanged';

  protected isFunction(obj: object) {
    return {}.toString.apply(obj) === '[object Function]';
  };

  protected isArray(obj: object) {
      return {}.toString.apply(obj) === '[object Array]';
  };

  protected isObject(obj: object) {
      return {}.toString.apply(obj) === '[object Object]';
  };

  protected isDate(obj: object) {
      return {}.toString.apply(obj) === '[object Date]';
  };

  protected isValue(obj: object) {
      return !this.isObject(obj) && !this.isArray(obj);
  };

  protected compareValues (value1: any, value2: any) {
    if (value1 === value2) {
        return deepDiffMapper.VALUE_UNCHANGED;
    }
    if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
        return deepDiffMapper.VALUE_UNCHANGED;
    }
    if ('undefined' == typeof(value1)) {
        return deepDiffMapper.VALUE_CREATED;
    }
    if ('undefined' == typeof(value2)) {
        return deepDiffMapper.VALUE_DELETED;
    }

    return deepDiffMapper.VALUE_UPDATED;
  }

  public map(obj1: object, obj2: object) {
      if (this.isFunction(obj1) || this.isFunction(obj2)) {
          throw 'Invalid argument. Function given, object expected.';
      }
      if (this.isValue(obj1) || this.isValue(obj2)) {
          return {
              type: this.compareValues(obj1, obj2),
              data: (obj1 === undefined) ? obj2 : obj1
          };
      }

      var diff = {};
      for (var key in obj1) {
          if (this.isFunction(obj1[key])) {
              continue;
          }

          var value2 = undefined;
          if ('undefined' != typeof(obj2[key])) {
              value2 = obj2[key];
          }

          diff[key] = this.map(obj1[key], value2);
      }
      for (var key in obj2) {
          if (this.isFunction(obj2[key]) || ('undefined' != typeof(diff[key]))) {
              continue;
          }

          diff[key] = this.map(undefined, obj2[key]);
      }

      return diff;

  }
}

const diff = require("deep-object-diff").diff;
let differences = diff(obj2, obj1);

매주 5 만 회 이상 다운로드되는 npm 모듈이 있습니다 : https://www.npmjs.com/package/deep-object-diff

차이점의 표현과 같은 객체를 좋아합니다. 특히 형식이 지정되면 구조를 쉽게 볼 수 있습니다.

const diff = require("deep-object-diff").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'
}
*/

나는 두 물체의 차이를 얻는 방법을 찾으려고 여기에서 우연히 발견했다. 이것은 Lodash를 사용하는 솔루션입니다.

// Get updated values (including new values)
var updatedValuesIncl = _.omitBy(curr, (value, key) => _.isEqual(last[key], value));

// Get updated values (excluding new values)
var updatedValuesExcl = _.omitBy(curr, (value, key) => (!_.has(last, key) || _.isEqual(last[key], value)));

// Get old values (by using updated values)
var oldValues = Object.keys(updatedValuesIncl).reduce((acc, key) => { acc[key] = last[key]; return acc; }, {});

// Get newly added values
var newCreatedValues = _.omitBy(curr, (value, key) => _.has(last, key));

// Get removed values
var deletedValues = _.omitBy(last, (value, key) => _.has(curr, key));

// Then you can group them however you want with the result

아래 코드 스 니펫 :

var last = {
"authed": true,
"inForeground": true,
"goodConnection": false,
"inExecutionMode": false,
"online": true,
"array": [1, 2, 3],
"deep": {
	"nested": "value",
},
"removed": "value",
};

var curr = {
"authed": true,
"inForeground": true,
"deep": {
	"nested": "changed",
},
"array": [1, 2, 4],
"goodConnection": true,
"inExecutionMode": false,
"online": false,
"new": "value"
};

// Get updated values (including new values)
var updatedValuesIncl = _.omitBy(curr, (value, key) => _.isEqual(last[key], value));
// Get updated values (excluding new values)
var updatedValuesExcl = _.omitBy(curr, (value, key) => (!_.has(last, key) || _.isEqual(last[key], value)));
// Get old values (by using updated values)
var oldValues = Object.keys(updatedValuesIncl).reduce((acc, key) => { acc[key] = last[key]; return acc; }, {});
// Get newly added values
var newCreatedValues = _.omitBy(curr, (value, key) => _.has(last, key));
// Get removed values
var deletedValues = _.omitBy(last, (value, key) => _.has(curr, key));

console.log('oldValues', JSON.stringify(oldValues));
console.log('updatedValuesIncl', JSON.stringify(updatedValuesIncl));
console.log('updatedValuesExcl', JSON.stringify(updatedValuesExcl));
console.log('newCreatedValues', JSON.stringify(newCreatedValues));
console.log('deletedValues', JSON.stringify(deletedValues));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

참고 URL : https://stackoverflow.com/questions/8572826/generic-deep-diff-between-two-objects

반응형