문제

엄격한 평등 연산자는 두 개체가 있는지 알려줍니다. 종류 같다.그러나 두 객체가 동일한지 알 수 있는 방법이 있습니까? 해시 코드와 매우 유사 자바의 가치?

스택 오버플로 질문 JavaScript에 어떤 종류의 hashCode 함수가 있습니까? 이 질문과 비슷하지만 좀 더 학문적인 답변이 필요합니다.위의 시나리오는 왜 그것이 필요한지 보여주며, 어떤 것이 있는지 궁금합니다. 동등한 솔루션.

도움이 되었습니까?

해결책

짧은 대답

간단한 대답은 다음과 같습니다. 아니요, 객체가 당신이 의미하는 의미에서 객체가 다른 물체와 동일하다고 판단 할 일반적인 수단이 없습니다. 예외는 당신이 타이핑이없는 것을 엄격히 생각할 때입니다.

긴 대답

개념은 객체의 두 가지 다른 인스턴스를 비교하여 값 수준에서 동등한지를 나타내는 개념입니다. 그러나 어떻게 Equals 방법을 구현해야합니다. 원시 값을 갖는 속성의 반복 비교로는 충분하지 않을 수 있으며, 객체 값의 일부로 간주되지 않는 속성이있을 수 있습니다. 예를 들어,

 function MyClass(a, b)
 {
     var c;
     this.getCLazy = function() {
         if (c === undefined) c = a * b // imagine * is really expensive
         return c;
     }
  }

위의 경우, c MyClass의 두 인스턴스가 동일했는지 여부를 결정하는 데 실제로는 중요하지 않습니다. a 그리고 b 중요하다. 일부 경우에 c 인스턴스마다 다를 수 있지만 비교 중에는 중요하지 않습니다.

참고이 문제는 회원 자체가 유형의 사례 일 때 적용되며 각각 평등을 결정하는 수단을 가져야합니다.

더욱 복잡한 것은 JavaScript에서 데이터와 방법의 구별이 흐려진다는 것입니다.

객체는 이벤트 핸들러라고 불리는 메소드를 참조 할 수 있으며, 이는 '가치 상태'의 일부로 간주되지 않을 수 있습니다. 반면 다른 객체는 중요한 계산을 수행하는 함수가 할당되어 다른 함수를 참조하기 때문에 다른 인스턴스와 다른 인스턴스와 다르게 만듭니다.

기존 프로토 타입 메소드 중 하나가 다른 기능에 의해 무시되는 객체는 어떻습니까? 여전히 다른 인스턴스와 동일하게 간주 될 수 있습니까? 이 질문은 각 유형의 각 특정 사례에서만 답변 할 수 있습니다.

앞서 언급했듯이 예외는 엄격하게 입력이없는 객체입니다. 이 경우 유일한 합리적인 선택은 각 구성원의 반복적이고 재귀적인 비교입니다. 그럼에도 불구하고 함수의 '가치'가 무엇인지 물어봐야합니까?

다른 팁

바퀴를 재발명하는 이유는 무엇입니까?주다 로다시 시도.등 다양한 필수 기능을 갖추고 있습니다. 는 같다().

_.isEqual(object, other);

이 페이지의 다른 예와 마찬가지로 각 키 값을 무차별 대입 검사합니다. ECMA스크립트 5 브라우저에서 사용 가능한 경우 기본 최적화가 가능합니다.

메모:이전에는 이 답변이 권장되었습니다. Underscore.js, 하지만 로다시 버그를 수정하고 일관성 있게 문제를 해결하는 작업을 더 잘 수행했습니다.

객체에 대한 JavaScript의 기본 평등 연산자는 메모리의 동일한 위치를 참조 할 때 사실을 산출합니다.

var x = {};
var y = {};
var z = x;

x === y; // => false
x === z; // => true

다른 평등 연산자가 필요한 경우 추가해야합니다. equals(other) 방법 또는 클래스와 같은 방법 및 문제 영역의 세부 사항은 정확히 그 의미를 결정합니다.

다음은 재생 카드 예입니다.

function Card(rank, suit) {
  this.rank = rank;
  this.suit = suit;
  this.equals = function(other) {
     return other.rank == this.rank && other.suit == this.suit;
  };
}

var queenOfClubs = new Card(12, "C");
var kingOfSpades = new Card(13, "S");

queenOfClubs.equals(kingOfSpades); // => false
kingOfSpades.equals(new Card(13, "S")); // => true

당신이 일하는 경우 Angularjs,, angular.equals 함수는 두 객체가 동일했는지 여부를 결정합니다. ~ 안에 ember.js 사용 isEqual.

  • angular.equals - 참조 문서 또는 원천 이 방법에 대한 자세한 내용. 배열에서도 깊은 비교를합니다.
  • ember.js isEqual - 참조 문서 또는 원천 이 방법에 대한 자세한 내용. 배열에서 깊은 비교를하지 않습니다.

var purple = [{"purple": "drank"}];
var drank = [{"purple": "drank"}];

if(angular.equals(purple, drank)) {
    document.write('got dat');
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>

이것은 내 버전입니다. 새로운 것을 사용하고 있습니다 객체 .keys ES5에서 소개 된 기능 및 아이디어/테스트 +, + 그리고 +:

function objectEquals(x, y) {
    'use strict';

    if (x === null || x === undefined || y === null || y === undefined) { return x === y; }
    // after this just checking type of one would be enough
    if (x.constructor !== y.constructor) { return false; }
    // if they are functions, they should exactly refer to same one (because of closures)
    if (x instanceof Function) { return x === y; }
    // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES)
    if (x instanceof RegExp) { return x === y; }
    if (x === y || x.valueOf() === y.valueOf()) { return true; }
    if (Array.isArray(x) && x.length !== y.length) { return false; }

    // if they are dates, they must had equal valueOf
    if (x instanceof Date) { return false; }

    // if they are strictly equal, they both need to be object at least
    if (!(x instanceof Object)) { return false; }
    if (!(y instanceof Object)) { return false; }

    // recursive object equality check
    var p = Object.keys(x);
    return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) &&
        p.every(function (i) { return objectEquals(x[i], y[i]); });
}


///////////////////////////////////////////////////////////////
/// The borrowed tests, run them by clicking "Run code snippet"
///////////////////////////////////////////////////////////////
var printResult = function (x) {
    if (x) { document.write('<div style="color: green;">Passed</div>'); }
    else { document.write('<div style="color: red;">Failed</div>'); }
};
var assert = { isTrue: function (x) { printResult(x); }, isFalse: function (x) { printResult(!x); } }
assert.isTrue(objectEquals(null,null));
assert.isFalse(objectEquals(null,undefined));
assert.isFalse(objectEquals(/abc/, /abc/));
assert.isFalse(objectEquals(/abc/, /123/));
var r = /abc/;
assert.isTrue(objectEquals(r, r));

assert.isTrue(objectEquals("hi","hi"));
assert.isTrue(objectEquals(5,5));
assert.isFalse(objectEquals(5,10));

assert.isTrue(objectEquals([],[]));
assert.isTrue(objectEquals([1,2],[1,2]));
assert.isFalse(objectEquals([1,2],[2,1]));
assert.isFalse(objectEquals([1,2],[1,2,3]));

assert.isTrue(objectEquals({},{}));
assert.isTrue(objectEquals({a:1,b:2},{a:1,b:2}));
assert.isTrue(objectEquals({a:1,b:2},{b:2,a:1}));
assert.isFalse(objectEquals({a:1,b:2},{a:1,b:3}));

assert.isTrue(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
assert.isFalse(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));

Object.prototype.equals = function (obj) { return objectEquals(this, obj); };
var assertFalse = assert.isFalse,
    assertTrue = assert.isTrue;

assertFalse({}.equals(null));
assertFalse({}.equals(undefined));

assertTrue("hi".equals("hi"));
assertTrue(new Number(5).equals(5));
assertFalse(new Number(5).equals(10));
assertFalse(new Number(1).equals("1"));

assertTrue([].equals([]));
assertTrue([1,2].equals([1,2]));
assertFalse([1,2].equals([2,1]));
assertFalse([1,2].equals([1,2,3]));
assertTrue(new Date("2011-03-31").equals(new Date("2011-03-31")));
assertFalse(new Date("2011-03-31").equals(new Date("1970-01-01")));

assertTrue({}.equals({}));
assertTrue({a:1,b:2}.equals({a:1,b:2}));
assertTrue({a:1,b:2}.equals({b:2,a:1}));
assertFalse({a:1,b:2}.equals({a:1,b:3}));

assertTrue({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
assertFalse({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));

var a = {a: 'text', b:[0,1]};
var b = {a: 'text', b:[0,1]};
var c = {a: 'text', b: 0};
var d = {a: 'text', b: false};
var e = {a: 'text', b:[1,0]};
var i = {
    a: 'text',
    c: {
        b: [1, 0]
    }
};
var j = {
    a: 'text',
    c: {
        b: [1, 0]
    }
};
var k = {a: 'text', b: null};
var l = {a: 'text', b: undefined};

assertTrue(a.equals(b));
assertFalse(a.equals(c));
assertFalse(c.equals(d));
assertFalse(a.equals(e));
assertTrue(i.equals(j));
assertFalse(d.equals(k));
assertFalse(k.equals(l));

// from comments on stackoverflow post
assert.isFalse(objectEquals([1, 2, undefined], [1, 2]));
assert.isFalse(objectEquals([1, 2, 3], { 0: 1, 1: 2, 2: 3 }));
assert.isFalse(objectEquals(new Date(1234), 1234));

// no two different function is equal really, they capture their context variables
// so even if they have same toString(), they won't have same functionality
var func = function (x) { return true; };
var func2 = function (x) { return true; };
assert.isTrue(objectEquals(func, func));
assert.isFalse(objectEquals(func, func2));
assert.isTrue(objectEquals({ a: { b: func } }, { a: { b: func } }));
assert.isFalse(objectEquals({ a: { b: func } }, { a: { b: func2 } }));

JSON 라이브러리를 사용하는 경우 각 객체를 JSON으로 인코딩 한 다음 결과 문자열을 평등과 비교할 수 있습니다.

var obj1={test:"value"};
var obj2={test:"value2"};

alert(JSON.encode(obj1)===JSON.encode(obj2));

참고 :이 답변은 많은 경우에 작동하지만 여러 사람들이 의견에서 지적했듯이 여러 가지 이유로 문제가됩니다. 거의 모든 경우에 더 강력한 솔루션을 찾고 싶습니다.

짧은 기능 deepEqual 구현:

function deepEqual(x, y) {
  return (x && y && typeof x === 'object' && typeof y === 'object') ?
    (Object.keys(x).length === Object.keys(y).length) &&
      Object.keys(x).reduce(function(isEqual, key) {
        return isEqual && deepEqual(x[key], y[key]);
      }, true) : (x === y);
}

편집하다: 버전 2, Jib의 제안 및 ES6 화살표 기능을 사용하여 :

function deepEqual(x, y) {
  const ok = Object.keys, tx = typeof x, ty = typeof y;
  return x && y && tx === 'object' && tx === ty ? (
    ok(x).length === ok(y).length &&
      ok(x).every(key => deepEqual(x[key], y[key]))
  ) : (x === y);
}

딥 카피 기능이 편리한 경우 다음 트릭을 사용할 수 있습니다. 아직 사용 JSON.stringify 속성 순서와 일치하는 동안 :

function equals(obj1, obj2) {
    function _equals(obj1, obj2) {
        return JSON.stringify(obj1)
            === JSON.stringify($.extend(true, {}, obj1, obj2));
    }
    return _equals(obj1, obj2) && _equals(obj2, obj1);
}

데모: http://jsfiddle.net/cu3vb/3/

이론적 해석:

속성 이후 obj1 클론에 하나씩 복사하면 클론의 순서가 보존됩니다. 그리고 속성이있을 때 obj2 이미 존재하는 속성이 있으므로 클론에 복사됩니다. obj1 단순히 덮어 쓸 것입니다. 클론에서의 명령은 보존됩니다.

두 객체가 동일한지 테스트하려고합니까? 즉, 그들의 속성은 동일합니까?

이 경우 이런 상황을 알게 될 것입니다.

var a = { foo : "bar" };
var b = { foo : "bar" };
alert (a == b ? "Equal" : "Not equal");
// "Not equal"

다음과 같은 일을해야 할 수도 있습니다.

function objectEquals(obj1, obj2) {
    for (var i in obj1) {
        if (obj1.hasOwnProperty(i)) {
            if (!obj2.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    for (var i in obj2) {
        if (obj2.hasOwnProperty(i)) {
            if (!obj1.hasOwnProperty(i)) return false;
            if (obj1[i] != obj2[i]) return false;
        }
    }
    return true;
}

분명히 그 기능은 약간의 최적화와 깊은 점검을 수행하는 기능 (중첩 된 물체를 처리하기 위해 : var a = { foo : { fu : "bar" } })하지만 당신은 아이디어를 얻습니다.

지적과 관련하여, 당신은 자신의 목적을 위해 이것을 조정해야 할 수도 있습니다. 평범한 물체로 작업하는 경우 위의만큼 충분할 수 있습니다. 그렇지 않으면 관습이 MyClass.equals() 기능은가는 길 일 수 있습니다.

가장 간단합니다 그리고 논리적 모든 것을 비교하기위한 솔루션 객체, 배열, 문자열, int ...

JSON.stringify({a: val1}) === JSON.stringify({a: val2})

메모:

  • 교체해야합니다 val1그리고 val2 당신의 대상으로
  • 객체의 경우 두 측면 객체에 대해 (키로) 재귀 적으로 정렬해야합니다.

Node.js에서는 원본을 사용할 수 있습니다 require("assert").deepEqual. 더 많은 정보:http://nodejs.org/api/assert.html

예를 들어:

var assert = require("assert");
assert.deepEqual({a:1, b:2}, {a:1, b:3}); // will throw AssertionError

반환되는 또 다른 예 true / false 반환 오류 대신 :

var assert = require("assert");

function deepEqual(a, b) {
    try {
      assert.deepEqual(a, b);
    } catch (error) {
      if (error.name === "AssertionError") {
        return false;
      }
      throw error;
    }
    return true;
};

나는 이것을 사용한다 comparable JSON 비교할 수있는 내 개체의 사본을 생성하는 기능 :

var comparable = o => (typeof o != 'object' || !o)? o :
  Object.keys(o).sort().reduce((c, key) => (c[key] = comparable(o[key]), c), {});

// Demo:

var a = { a: 1, c: 4, b: [2, 3], d: { e: '5', f: null } };
var b = { b: [2, 3], c: 4, d: { f: null, e: '5' }, a: 1 };

console.log(JSON.stringify(comparable(a)));
console.log(JSON.stringify(comparable(b)));
console.log(JSON.stringify(comparable(a)) == JSON.stringify(comparable(b)));
<div id="div"></div>

테스트에 편리합니다 (대부분의 테스트 프레임 워크에는 is 기능). 예를 들어

is(JSON.stringify(comparable(x)), JSON.stringify(comparable(y)), 'x must match y');

차이가 잡히면 문자열이 기록되어 차이가 스포츠 가능합니다.

x must match y
got      {"a":1,"b":{"0":2,"1":3},"c":7,"d":{"e":"5","f":null}},
expected {"a":1,"b":{"0":2,"1":3},"c":4,"d":{"e":"5","f":null}}.

Heres는 기능 스타일 접근법을 사용하여 ES6/ES2015의 솔루션입니다.

const typeOf = x => 
  ({}).toString
      .call(x)
      .match(/\[object (\w+)\]/)[1]

function areSimilar(a, b) {
  const everyKey = f => Object.keys(a).every(f)

  switch(typeOf(a)) {
    case 'Array':
      return a.length === b.length &&
        everyKey(k => areSimilar(a.sort()[k], b.sort()[k]));
    case 'Object':
      return Object.keys(a).length === Object.keys(b).length &&
        everyKey(k => areSimilar(a[k], b[k]));
    default:
      return a === b;
  }
}

여기에서 사용 가능한 데모

누군가가 이와 비슷한 것을 게시했는지는 모르겠지만, 객체 평등성을 확인하기 위해 만든 기능이 있습니다.

function objectsAreEqual(a, b) {
  for (var prop in a) {
    if (a.hasOwnProperty(prop)) {
      if (b.hasOwnProperty(prop)) {
        if (typeof a[prop] === 'object') {
          if (!objectsAreEqual(a[prop], b[prop])) return false;
        } else {
          if (a[prop] !== b[prop]) return false;
        }
      } else {
        return false;
      }
    }
  }
  return true;
}

또한 재귀 적이므로 깊은 평등을 확인할 수도 있습니다.

당신이 사용할 수있는 _.isEqual(obj1, obj2) alterscore.js 라이브러리에서.

예는 다음과 같습니다.

var stooge = {name: 'moe', luckyNumbers: [13, 27, 34]};
var clone  = {name: 'moe', luckyNumbers: [13, 27, 34]};
stooge == clone;
=> false
_.isEqual(stooge, clone);
=> true

여기에서 공식 문서를 참조하십시오. http://underscorejs.org/#isequal

많은 사람들이 깨닫지 못하는이 문제에 대한 간단한 해결책은 JSON 현을 정렬하는 것입니다 (캐릭터 당). 이것은 일반적으로 여기에 언급 된 다른 솔루션보다 빠릅니다.

function areEqual(obj1, obj2) {
    var a = JSON.stringify(obj1), b = JSON.stringify(obj2);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}

이 방법에 대한 또 다른 유용한 점은 JSON.Stringify 함수에 "대체기"기능을 전달하여 비교를 필터링 할 수 있다는 것입니다.https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/json/stringify#example_of_using_replacer_parameter). 다음은 "derp"라는 모든 객체 키를 비교합니다.

function areEqual(obj1, obj2, filter) {
    var a = JSON.stringify(obj1, filter), b = JSON.stringify(obj2, filter);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}
var equal = areEqual(obj1, obj2, function(key, value) {
    return (key === 'derp') ? value : undefined;
});

하싱 또는 직렬화에 대해 조언합니다 (JSON 솔루션이 제안한대로). 두 객체가 동일했는지 여부를 테스트 해야하는 경우 동등한 의미를 정의해야합니다. 두 객체의 모든 데이터 멤버가 일치하거나 메모리 위치가 일치해야 할 수도 있습니다 (두 변수는 모두 메모리에서 동일한 객체를 참조 함) 또는 각 객체의 하나의 데이터 구성원 만 일치해야 할 수도 있습니다.

최근에 인스턴스가 생성 될 때마다 생성자가 새 ID (1부터 1에서 시작하여 1 점 증가)를 만드는 객체를 개발했습니다. 이 객체에는 해당 ID 값을 다른 객체의 ID 값과 비교하고 일치하는 경우 TRUE를 반환하는 ISEQUAL 기능이 있습니다.

이 경우 "동일"을 ID 값이 일치하는 것으로 정의했습니다. 각 인스턴스에 고유 한 ID가 있다는 점을 감안할 때 이것은 일치하는 객체가 동일한 메모리 위치를 차지한다는 아이디어를 시행하는 데 사용될 수 있습니다. 필요하지는 않지만.

게시 된 것보다 더 일반적인 객체 비교 함수가 필요하면 다음을 요리했습니다. 비평은 감사합니다 ...

Object.prototype.equals = function(iObj) {
  if (this.constructor !== iObj.constructor)
    return false;
  var aMemberCount = 0;
  for (var a in this) {
    if (!this.hasOwnProperty(a))
      continue;
    if (typeof this[a] === 'object' && typeof iObj[a] === 'object' ? !this[a].equals(iObj[a]) : this[a] !== iObj[a])
      return false;
    ++aMemberCount;
  }
  for (var a in iObj)
    if (iObj.hasOwnProperty(a))
      --aMemberCount;
  return aMemberCount ? false : true;
}

JSON 객체를 비교하는 경우 사용할 수 있습니다 https://github.com/mirek/node-rus-diff

npm install rus-diff

용법:

a = {foo:{bar:1}}
b = {foo:{bar:1}}
c = {foo:{bar:2}}

var rusDiff = require('rus-diff').rusDiff

console.log(rusDiff(a, b)) // -> false, meaning a and b are equal
console.log(rusDiff(a, c)) // -> { '$set': { 'foo.bar': 2 } }

두 객체가 다르면 MongoDB와 호환됩니다 {$rename:{...}, $unset:{...}, $set:{...}} 객체가 반환됩니다.

나는 같은 문제에 직면하여 내 자신의 해결책을 작성하기 위해 결정되었다. 그러나 배열을 물체와 비교하고 그 반대로 비교하고 싶기 때문에 일반 솔루션을 만들었습니다. 프로토 타입에 기능을 추가하기로 결정했지만 독립형 기능으로 쉽게 다시 작성할 수 있습니다. 코드는 다음과 같습니다.

Array.prototype.equals = Object.prototype.equals = function(b) {
    var ar = JSON.parse(JSON.stringify(b));
    var err = false;
    for(var key in this) {
        if(this.hasOwnProperty(key)) {
            var found = ar.find(this[key]);
            if(found > -1) {
                if(Object.prototype.toString.call(ar) === "[object Object]") {
                    delete ar[Object.keys(ar)[found]];
                }
                else {
                    ar.splice(found, 1);
                }
            }
            else {
                err = true;
                break;
            }
        }
    };
    if(Object.keys(ar).length > 0 || err) {
        return false;
    }
    return true;
}

Array.prototype.find = Object.prototype.find = function(v) {
    var f = -1;
    for(var i in this) {
        if(this.hasOwnProperty(i)) {
            if(Object.prototype.toString.call(this[i]) === "[object Array]" || Object.prototype.toString.call(this[i]) === "[object Object]") {
                if(this[i].equals(v)) {
                    f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
                }
            }
            else if(this[i] === v) {
                f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
            }
        }
    }
    return f;
}

이 알고리즘은 두 부분으로 나뉩니다. 동등한 기능 자체와 기능은 배열 / 객체에서 속성의 숫자 색인을 찾는 기능입니다. 인덱스는 숫자와 문자열과 객체 만 찾지 않기 때문에 찾기 기능은 필요합니다.

이것을 다음과 같이 부를 수 있습니다.

({a: 1, b: "h"}).equals({a: 1, b: "h"});

함수는 TRUE 또는 FALSE를 반환 하고이 경우 true입니다. 알고리즘 ALS는 매우 복잡한 객체를 비교할 수 있습니다.

({a: 1, b: "hello", c: ["w", "o", "r", "l", "d", {answer1: "should be", answer2: true}]}).equals({b: "hello", a: 1, c: ["w", "d", "o", "r", {answer1: "should be", answer2: true}, "l"]})

상단 예제는 true를 반환 할 것이며, 심지어 속성은 다른 순서를 갖습니다. 찾아야 할 작은 세부 사항 중 하나 :이 코드는 동일한 유형의 두 변수를 확인하므로 "3"은 3과 다릅니다.

일부 ES6 기능을 사용하여 내 버전의 객체 비교에 기여하고 싶었습니다. 주문을 고려하지 않습니다. 모든 if/else 's를 Ternary로 변환 한 후 다음과 같이 왔습니다.

function areEqual(obj1, obj2) {

    return Object.keys(obj1).every(key => {

            return obj2.hasOwnProperty(key) ?
                typeof obj1[key] === 'object' ?
                    areEqual(obj1[key], obj2[key]) :
                obj1[key] === obj2[key] :
                false;

        }
    )
}

모든 속성에 대해 동일한 값이 모두 동일하고 모든 중첩 된 객체 및 배열에 대해 재귀 적으로 두 개의 객체를 동일하게 고려하는 것이 유용합니다. 나는 또한 다음 두 개체를 동일하다고 생각합니다.

var a = {p1: 1};
var b = {p1: 1, p2: undefined};

마찬가지로 배열에는 "누락 된"요소와 정의되지 않은 요소가있을 수 있습니다. 나는 그것들도 똑같이 취급 할 것입니다.

var c = [1, 2];
var d = [1, 2, undefined];

평등의 정의를 구현하는 기능 :

function isEqual(a, b) {
    if (a === b) {
        return true;
    }

    if (generalType(a) != generalType(b)) {
        return false;
    }

    if (a == b) {
        return true;
    }

    if (typeof a != 'object') {
        return false;
    }

    // null != {}
    if (a instanceof Object != b instanceof Object) {
        return false;
    }

    if (a instanceof Date || b instanceof Date) {
        if (a instanceof Date != b instanceof Date ||
            a.getTime() != b.getTime()) {
            return false;
        }
    }

    var allKeys = [].concat(keys(a), keys(b));
    uniqueArray(allKeys);

    for (var i = 0; i < allKeys.length; i++) {
        var prop = allKeys[i];
        if (!isEqual(a[prop], b[prop])) {
            return false;
        }
    }
    return true;
}

소스 코드 (도우미 기능, GeneralType 및 IliqueArray 포함) :단위 테스트 그리고 여기 테스트 러너.

이 기능으로 다음과 같은 가정을하고 있습니다.

  1. 비교하는 객체를 제어하고 원시 값 (예 : 중첩 된 객체, 함수 등) 만 있습니다.
  2. 브라우저가 지원합니다 객체 .keys.

이것은 간단한 전략의 데모로 취급되어야합니다.

/**
 * Checks the equality of two objects that contain primitive values. (ie. no nested objects, functions, etc.)
 * @param {Object} object1
 * @param {Object} object2
 * @param {Boolean} [order_matters] Affects the return value of unordered objects. (ex. {a:1, b:2} and {b:2, a:1}).
 * @returns {Boolean}
 */
function isEqual( object1, object2, order_matters ) {
    var keys1 = Object.keys(object1),
        keys2 = Object.keys(object2),
        i, key;

    // Test 1: Same number of elements
    if( keys1.length != keys2.length ) {
        return false;
    }

    // If order doesn't matter isEqual({a:2, b:1}, {b:1, a:2}) should return true.
    // keys1 = Object.keys({a:2, b:1}) = ["a","b"];
    // keys2 = Object.keys({b:1, a:2}) = ["b","a"];
    // This is why we are sorting keys1 and keys2.
    if( !order_matters ) {
        keys1.sort();
        keys2.sort();
    }

    // Test 2: Same keys
    for( i = 0; i < keys1.length; i++ ) {
        if( keys1[i] != keys2[i] ) {
            return false;
        }
    }

    // Test 3: Values
    for( i = 0; i < keys1.length; i++ ) {
        key = keys1[i];
        if( object1[key] != object2[key] ) {
            return false;
        }
    }

    return true;
}

이는 위의 모든 항목에 대한 추가 항목이지 대체 항목이 아닙니다.추가 재귀 사례를 확인할 필요 없이 객체를 빠르게 얕은 비교해야 하는 경우.여기 샷이 있습니다.

이는 다음과 비교됩니다.1) 자신의 속성 개수 동일, 2) 키 이름 동일, 3) bCompareValues ​​== true인 경우 해당 속성 값과 해당 유형의 동일(삼중 동일)

var shallowCompareObjects = function(o1, o2, bCompareValues) {
    var s, 
        n1 = 0,
        n2 = 0,
        b  = true;

    for (s in o1) { n1 ++; }
    for (s in o2) { 
        if (!o1.hasOwnProperty(s)) {
            b = false;
            break;
        }
        if (bCompareValues && o1[s] !== o2[s]) {
            b = false;
            break;
        }
        n2 ++;
    }
    return b && n1 == n2;
}

간단한 키/값 쌍 객체 인스턴스의 키를 비교하려면 다음을 사용합니다.

function compareKeys(r1, r2) {
    var nloops = 0, score = 0;
    for(k1 in r1) {
        for(k2 in r2) {
            nloops++;
            if(k1 == k2)
                score++; 
        }
    }
    return nloops == (score * score);
};

키를 비교하면 간단한 추가가 추가됩니다 for..in 루프로 충분합니다.

복잡성은 O (n*n)이며 n은 키 수입니다.

나는 내가 정의하는 물체가 1000 개를 넘지 않는 것을 희망합니다 ...

나는 이것이 조금 늙었다는 것을 알고 있지만,이 문제에 대해 내가 생각해 낸 솔루션을 추가하고 싶습니다. 나는 물체가 있었고 데이터가 언제 변경되었는지 알고 싶었습니다. "Object.observe와 비슷한 것"그리고 내가 한 것은 다음과 같습니다.

function checkObjects(obj,obj2){
   var values = [];
   var keys = [];
   keys = Object.keys(obj);
   keys.forEach(function(key){
      values.push(key);
   });
   var values2 = [];
   var keys2 = [];
   keys2 = Object.keys(obj2);
   keys2.forEach(function(key){
      values2.push(key);
   });
   return (values == values2 && keys == keys2)
}

여기에서 복제되어 값과 키를 비교하기 위해 다른 배열 세트를 만들 수 있습니다. 이제 배열이기 때문에 매우 간단하고 객체의 크기가 다른 경우 False를 반환합니다.

내 작업에 반복적으로 사용하는 개인 도서관에서 꺼내는 것. 다음 함수는 관대 확인하지 않습니다

  • 계급 평등
  • 상속 된 값
  • 엄격한 평등 가치

나는 주로 다양한 API 구현에 대해 동등한 답변을 받는지 확인하기 위해 이것을 사용합니다. 구현 차이 (문자열 vs 숫자와 같은) 및 추가 널 값이 발생할 수 있습니다.

구현은 매우 간단하고 짧습니다 (모든 의견이 제거 된 경우)

/** Recursively check if both objects are equal in value
***
*** This function is designed to use multiple methods from most probable 
*** (and in most cases) valid, to the more regid and complex method.
***
*** One of the main principles behind the various check is that while
*** some of the simpler checks such as == or JSON may cause false negatives,
*** they do not cause false positives. As such they can be safely run first.
***
*** # !Important Note:
*** as this function is designed for simplified deep equal checks it is not designed
*** for the following
***
*** - Class equality, (ClassA().a = 1) maybe valid to (ClassB().b = 1)
*** - Inherited values, this actually ignores them
*** - Values being strictly equal, "1" is equal to 1 (see the basic equality check on this)
*** - Performance across all cases. This is designed for high performance on the
***   most probable cases of == / JSON equality. Consider bench testing, if you have
***   more 'complex' requirments
***
*** @param  objA : First object to compare
*** @param  objB : 2nd object to compare
*** @param  .... : Any other objects to compare
***
*** @returns true if all equals, or false if invalid
***
*** @license Copyright by eugene@picoded.com, 2012.
***          Licensed under the MIT license: http://opensource.org/licenses/MIT
**/
function simpleRecusiveDeepEqual(objA, objB) {
	// Multiple comparision check
	//--------------------------------------------
	var args = Array.prototype.slice.call(arguments);
	if(args.length > 2) {
		for(var a=1; a<args.length; ++a) {
			if(!simpleRecusiveDeepEqual(args[a-1], args[a])) {
				return false;
			}
		}
		return true;
	} else if(args.length < 2) {
		throw "simpleRecusiveDeepEqual, requires atleast 2 arguments";
	}
	
	// basic equality check,
	//--------------------------------------------
	// if this succed the 2 basic values is equal,
	// such as numbers and string.
	//
	// or its actually the same object pointer. Bam
	//
	// Note that if string and number strictly equal is required
	// change the equality from ==, to ===
	//
	if(objA == objB) {
		return true;
	}
	
	// If a value is a bsic type, and failed above. This fails
	var basicTypes = ["boolean", "number", "string"];
	if( basicTypes.indexOf(typeof objA) >= 0 || basicTypes.indexOf(typeof objB) >= 0 ) {
		return false;
	}
	
	// JSON equality check,
	//--------------------------------------------
	// this can fail, if the JSON stringify the objects in the wrong order
	// for example the following may fail, due to different string order:
	//
	// JSON.stringify( {a:1, b:2} ) == JSON.stringify( {b:2, a:1} )
	//
	if(JSON.stringify(objA) == JSON.stringify(objB)) {
		return true;
	}
	
	// Array equality check
	//--------------------------------------------
	// This is performed prior to iteration check,
	// Without this check the following would have been considered valid
	//
	// simpleRecusiveDeepEqual( { 0:1963 }, [1963] );
	//
	// Note that u may remove this segment if this is what is intended
	//
	if( Array.isArray(objA) ) {
		//objA is array, objB is not an array
		if( !Array.isArray(objB) ) {
			return false;
		}
	} else if( Array.isArray(objB) ) {
		//objA is not array, objB is an array
		return false;
	}
	
	// Nested values iteration
	//--------------------------------------------
	// Scan and iterate all the nested values, and check for non equal values recusively
	//
	// Note that this does not check against null equality, remove the various "!= null"
	// if this is required
	
	var i; //reuse var to iterate
	
	// Check objA values against objB
	for (i in objA) {
		//Protect against inherited properties
		if(objA.hasOwnProperty(i)) {
			if(objB.hasOwnProperty(i)) {
				// Check if deep equal is valid
				if(!simpleRecusiveDeepEqual( objA[i], objB[i] )) {
					return false;
				}
			} else if(objA[i] != null) {
				//ignore null values in objA, that objB does not have
				//else fails
				return false;
			}
		}
	}
	
	// Check if objB has additional values, that objA do not, fail if so
	for (i in objB) {
		if(objB.hasOwnProperty(i)) {
			if(objB[i] != null && !objA.hasOwnProperty(i)) {
				//ignore null values in objB, that objA does not have
				//else fails
				return false;
			}
		}
	}
	
	// End of all checks
	//--------------------------------------------
	// By reaching here, all iteration scans have been done.
	// and should have returned false if it failed
	return true;
}

// Sanity checking of simpleRecusiveDeepEqual
(function() {
	if(
		// Basic checks
		!simpleRecusiveDeepEqual({}, {}) ||
		!simpleRecusiveDeepEqual([], []) ||
		!simpleRecusiveDeepEqual(['a'], ['a']) ||
		// Not strict checks
		!simpleRecusiveDeepEqual("1", 1) ||
		// Multiple objects check
		!simpleRecusiveDeepEqual( { a:[1,2] }, { a:[1,2] }, { a:[1,2] } ) ||
		// Ensure distinction between array and object (the following should fail)
		simpleRecusiveDeepEqual( [1963], { 0:1963 } ) ||
		// Null strict checks
		simpleRecusiveDeepEqual( 0, null ) ||
		simpleRecusiveDeepEqual( "", null ) ||
		// Last "false" exists to make the various check above easy to comment in/out
		false
	) {
		alert("FATAL ERROR: simpleRecusiveDeepEqual failed basic checks");
	} else { 
		//added this last line, for SO snippet alert on success
		alert("simpleRecusiveDeepEqual: Passed all checks, Yays!");
	}
})();

다음은 타이핑이 적고 사소한 JSON 데이터 비교를 위해 많은 경우에 작동하는 Stringify 트릭 버전입니다.

var obj1Fingerprint = JSON.stringify(obj1).replace(/\{|\}/g,'').split(',').sort().join(',');
var obj2Fingerprint = JSON.stringify(obj2).replace(/\{|\}/g,'').split(',').sort().join(',');
if ( obj1Fingerprint === obj2Fingerprint) { ... } else { ... }

스파게티 코드 답변이 보입니다. 제 3 자 Libs를 사용하지 않으면 매우 쉽습니다.

먼저 두 객체를 키 이름으로 정렬하십시오.

let objectOne = { hey, you }
let objectTwo = { you, hey }

// If you really wanted you could make this recursive for deep sort.
const sortObjectByKeyname = (objectToSort) => {
    return Object.keys(objectToSort).sort().reduce((r, k) => (r[k] = objectToSort[k], r), {});
}

let objectOne = sortObjectByKeyname(objectOne)
let objectTwo = sortObjectByKeyname(objectTwo)

그런 다음 문자열을 사용하여 비교하십시오.

JSON.stringify(objectOne) === JSON.stringify(objectTwo)

nodejs를 사용하는 사람들에게는 편리한 방법이 있습니다. isDeepStrictEqual 이를 달성 할 수있는 기본 UTIL 라이브러리에서.

const util = require('util');

const foo = {
  hey: "ho",
  lets: "go"
}

const bar = {
  hey: "ho",
  lets: "go"
}

foo == bar // false
util.isDeepStrictEqual(foo, bar) // true

https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top