[javascript] 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 };

_.isEqual(a, b); // returns false if different

그러나이 솔루션은 어떤 속성이 다른지 보여주지 않습니다.

http://jsfiddle.net/bdkeyn0h/


답변

어떤 속성이 다른지 알아야하는 경우 reduce ()를 사용하십시오 .

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

답변

이 스레드를 다루는 모든 사람을 위해 더 완벽한 솔루션이 있습니다. 그것은 비교합니다 두 개체를 당신에게 중 모든 속성의 키주는 유일한 오브젝트 1 년을 , 단지 object2에서 , 또는이다 오브젝트 1 및 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;
}

이 스 니펫을 사용하여 코드를 시도 할 수 있습니다 (전체 페이지 모드에서 실행하는 것이 좋습니다).


답변

간결한 솔루션은 다음과 같습니다.

_.differenceWith(a, b, _.isEqual);

답변

객체가 다른 객체와 어떻게 다른지 재귀 적으로 보여주기 위해 _.isduce_.isEqual_.isPlainObject를 사용할 수 있습니다 . 이 경우 a와 b의 차이점 또는 b와 a의 차이점을 비교할 수 있습니다.

var a = {prop1: {prop1_1: 'text 1', prop1_2: 'text 2', prop1_3: [1, 2, 3]}, prop2: 2, prop3: 3};
var b = {prop1: {prop1_1: 'text 1', prop1_3: [1, 2]}, prop2: 2, prop3: 4};

var diff = function(obj1, obj2) {
  return _.reduce(obj1, function(result, value, key) {
    if (_.isPlainObject(value)) {
      result[key] = diff(value, obj2[key]);
    } else if (!_.isEqual(value, obj2[key])) {
      result[key] = value;
    }
    return result;
  }, {});
};

var res1 = diff(a, b);
var res2 = diff(b, a);
console.log(res1);
console.log(res2);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.4/lodash.min.js"></script>


답변

간단한 사용 _.isEqual방법, 그것은 모든 비교를 위해 작동합니다 …

  • 참고 : 이 방법은 배열, 배열 버퍼, 부울, * 날짜 오브젝트, 오류 오브젝트, 맵, 숫자, Object오브젝트, 정규 표현식, * 세트, 문자열, 기호 및 유형 배열 비교를 지원합니다. Object객체는 상속 가능하지 않고 열거 가능한 속성으로 * 비교됩니다. 함수 및 DOM * 노드는 지원 되지 않습니다 .

아래에 있다면 :

 const firstName = {name: "Alireza"};
 const otherName = {name: "Alireza"};

당신이 할 경우 : _.isEqual(firstName, otherName); ,

돌아올 것이다 사실 합니다

그리고 만약 const fullName = {firstName: "Alireza", familyName: "Dezfoolian"};

당신이 할 경우 : _.isEqual(firstName, fullName); ,

거짓 을 반환합니다