Frage

Eine strikte Gleichheitsoperator wird Ihnen sagen, ob zwei Objekt Typen gleich sind.Jedoch gibt es eine Möglichkeit zu sagen, ob zwei Objekte gleich sind, ähnlich wie der hash-code Wert in Java?

Stack-Overflow-Frage Gibt es irgendeine Art von hashCode-Funktion in JavaScript? ist ähnlich wie diese Frage, aber erfordert eine weitere Akademische Antwort.Die oben beschriebenen Szenario zeigt, warum es notwendig wäre, eine zu haben, und ich wundere mich, wenn es ist jede gleichwertige Lösung.

War es hilfreich?

Lösung

Die kurze Antwort

Die einfache Antwort ist: Nein, es gibt keine Generika Mittel, um festzustellen, dass ein Objekt zu einem anderen in dem Sinne gleich Sie meinen. Die Ausnahme ist, wenn Sie streng sind ein Objekt seines typenlos denken.

Die lange Antwort

Das Konzept besteht darin, dass die eine Methode Equals, die zwei verschiedene Instanzen eines Objekts vergleicht, um anzuzeigen, ob sie auf einem Wert Ebene gleich sind. Es ist jedoch auf die spezifische Aktivität von bis zu definieren, wie ein Equals Verfahren implementiert werden soll. Ein iterativer Vergleich von Attributen, die primitiven Werte haben nicht genug sein können, kann es durchaus Attribute sein, die nicht Teil des Objektwertes berücksichtigt werden. Zum Beispiel:

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

In diesem obigen Fall c nicht wirklich wichtig ist, um zu bestimmen, ob zwei Instanzen von MyClass gleich sind, nur a und b sind wichtig. In einigen Fällen c könnte zwischen den Instanzen unterschiedlich sein und noch nicht beim Vergleich von Bedeutung sein.

Hinweis: Dieses Problem gilt, wenn die Mitglieder können sich auch Instanzen eines Typs sein und diese jeweils alle erforderlich wären, ein Mittel zur Bestimmung der Gleichstellung haben.

Weitere Dinge zu komplizieren, ist, dass die Unterscheidung zwischen Daten in JavaScript und Verfahren verschwommen ist.

Ein Objekt kann ein Verfahren verweisen, die als Event-Handler aufgerufen werden soll, und dies würde wahrscheinlich nicht Teil seines ‚Wert Zustand‘ betrachtet werden. Während andere Aufgabe auch eine Funktion zugeordnet werden kann, die eine wichtige Berechnung durchführt und macht damit diese Instanz von anderen unterscheidet, nur weil sie eine andere Funktion verweist.

Was ist ein Objekt, das durch eine andere Funktion außer Kraft gesetzt eines ihrer bestehenden Prototyp Methoden hat? Könnte es noch gleich, dass es ansonsten identisch mit einem anderen Fall in Betracht gezogen werden? Diese Frage kann nur im Einzelfall für jede Art beantwortet werden.

Wie bereits erwähnt, wäre die Ausnahme ein streng typenlos Objekt. In diesem Fall ist die einzig sinnvolle Wahl ist ein iterativer und rekursive Vergleich jeden Mitglieds. Auch dann muss man sich fragen, was ist der ‚Wert‘ einer Funktion?

Andere Tipps

Warum das Rad neu erfinden? Geben Sie Lodash versuchen. Es hat eine Reihe von must-have Funktionen wie isEqual () .

_.isEqual(object, other);

Es wird Brute jeden Schlüsselwert Kraft kontrollieren - genau wie die anderen Beispiele auf dieser Seite - mit ECMAScript 5 und nativen Optimierungen, wenn sie im Browser verfügbar ist.

Hinweis: Zuvor diese Antwort empfohlen Underscore.js , aber lodash hat einen besseren Job gemacht Fehler behoben immer und Probleme mit Konsistenz Adressierung.

Der Standardgleichheitsoperator in JavaScript für Objekte ergibt wahr, wenn sie an der gleichen Stelle im Speicher verweisen.

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

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

Wenn Sie einen anderen Gleichheitsoperator benötigen, müssen Sie eine equals(other) Methode oder etwas wie es um Ihre Klassen und die Besonderheiten des Problem Domäne hinzufügen werden bestimmen, was genau das bedeutet.

Hier ist eine Spielkarte Beispiel:

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

Wenn Sie arbeiten in AngularJS wird die angular.equals Funktion bestimmen, ob zwei Objekte gleich sind. In Ember.js Verwendung isEqual.

  • angular.equals - Siehe docs oder Quelle mehr über diese Methode. Es ist ein tief zu auf Arrays vergleichen.
  • Ember.js isEqual - Siehe docs oder source für mehr auf diesem Verfahren. Es tut nicht tief auf Arrays vergleichen.

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>

Das ist meine Version. Es wird mit neuen Object.keys Funktion, die in ES5 und Ideen / Tests von + , + und + :

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 } }));

Wenn Sie eine JSON-Bibliothek verwenden, können Sie jedes Objekt als JSON kodieren, dann die resultierenden Strings auf Gleichheit vergleichen.

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

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

Hinweis: Während diese Antwort in vielen Fällen funktionieren wird, da mehrere Menschen in den Kommentaren darauf hingewiesen haben, es ist problematisch für eine Vielzahl von Gründen. In so ziemlich allen Fällen werden Sie wollen eine robustere Lösung finden.

Kurze Funktions deepEqual Umsetzung:

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);
}

Bearbeiten : Version 2, mit Auslegern Anregung und ES6 Pfeil Funktionen:

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);
}

Wenn Sie eine tiefe Kopierfunktion zur Hand haben, können Sie den folgenden Trick, um verwenden noch Verwendung JSON.stringify während der Reihenfolge der Objekte in dieser Auswahl:

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);
}

Demo: http://jsfiddle.net/CU3vb/3/

Begründung:

Da die Eigenschaften von obj1 auf den Klon eines nach dem anderen kopiert werden, deren Reihenfolge in der Klon bleiben erhalten. Und wenn die Eigenschaften von obj2 auf den Klon kopiert werden, da Eigenschaften bereits in obj1 bestehenden einfach überschrieben werden, ihre Aufträgen im Klon bleiben erhalten.

Versuchen Sie, zu testen, ob zwei Objekte, die gleich sind? dh: ihre Eigenschaften sind gleich

Wenn dies der Fall ist, werden Sie wahrscheinlich diese Situation haben bemerkt:

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

Sie könnte so etwas zu tun haben:

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;
}

Offensichtlich diese Funktion könnte mit ziemlich viel Optimierung zu tun, und die Fähigkeit, tiefe Prüfung zu tun (verschachtelte Objekte zu behandeln: var a = { foo : { fu : "bar" } }). Aber Sie bekommen die Idee

Wie für wies darauf hin, könnten Sie dies für Ihre eigenen Zwecke anpassen müssen, zB: verschiedene Klassen unterschiedliche Definitionen von „equal“ haben kann. Wenn Sie nur mit einfachen Objekten arbeiten, genügen die oben kann, sonst eine benutzerdefinierte MyClass.equals() Funktion der richtige Weg sein kann zu gehen.

Einfachstes und logische Lösungen für den Vergleich alles wie Objekt, Array, String, Int ...

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

Hinweis:

  • Sie müssen val1and val2 mit Ihrem Objekt
  • ersetzen
  • für das Objekt, müssen Sie (mit Schlüssel) sortieren rekursiv für beide Seiten-Objekte

In Node.js, können Sie seine native require("assert").deepEqual verwenden. Mehr Info: http://nodejs.org/api/assert.html

Zum Beispiel:

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

Ein weiteres Beispiel, das true / false statt Rückkehr Fehler zurückgibt:

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;
};

Ich benutze diese Funktion comparable Kopien meiner Objekte zu erzeugen, die JSON vergleichbar sind:

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>

ist praktisch in Tests (die meist Test-Frameworks hat eine is-Funktion). Z.

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

Wenn ein Unterschied gefangen ist, werden Strings protokolliert werden, so dass Unterschiede spottable:

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 ist eine Lösung in ES6 / ES2015 einen funktionalen Stil Ansatz:

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;
  }
}

Demo verfügbar hier

Ich weiß nicht, ob jemand etwas ähnlich wie diese geschrieben hat, aber hier ist eine Funktion, die ich gemacht für Objekt Gleichheiten zu überprüfen.

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;
}

Außerdem ist es rekursiv, so kann es auch für tiefe Gleichheit überprüfen, ob das, was Sie es nennen.

Sie _.isEqual(obj1, obj2) aus der Underscore.js Bibliothek verwenden können.

Hier ist ein Beispiel:

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

Sehen Sie die offizielle Dokumentation von hier: http://underscorejs.org/#isEqual

Eine einfache Lösung für dieses Problem, dass viele Menschen nicht wissen, ist die JSON-Strings zu sortieren (pro Zeichen). Dies ist auch in der Regel schneller als die anderen Lösungen, die hier erwähnt:

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(''));
}

Eine weitere nützliche an dieser Methode ist, dass Sie Vergleiche filtern kann eine „replacer“ -Funktion auf die JSON.stringify Funktionen (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Example_of_using_replacer_parameter ). Im Folgenden wird nur alle Objekte Tasten vergleichen, die „derp“ genannt werden:

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;
});

Ich würde davon abraten, Hashing oder Serialisierung (wie die JSON-Lösung vorschlagen). Wenn Sie testen müssen, ob zwei Objekte gleich sind, dann müssen Sie festlegen, welche Mittel entspricht. Es könnte sein, dass alle Datenelemente in beiden Objekten übereinstimmen, oder könnte es sein, dass muss die Speicherplatz Spiel (was bedeutet, beide Variablen verweisen auf dasselbe Objekt im Speicher), oder kann sein, dass nur ein Datenelement in jedem Objekt übereinstimmen muß.

Vor kurzem entwickelte ich ein Objekt, dessen Konstruktor erstellt eine neue ID (ab 1 und um 1 erhöht) jedes Mal, wenn eine Instanz erstellt wird. Dieses Objekt hat eine isEqual Funktion, dass die ID-Wert mit dem ID-Wert eines anderen Objekts vergleicht und gibt true zurück, wenn sie übereinstimmen.

In diesem Fall definiert I „gleich“ versteht man das die ID-Werte übereinstimmen. Da jede Instanz eine eindeutige ID hat diese verwendet werden, um die Idee zu erzwingen, dass passenden Objekte auch den gleichen Speicherplatz belegen. Obwohl das ist nicht notwendig.

ein allgemeineres Objekt Vergleichsfunktion Needing als geschrieben worden war, kochte ich folgendes auf. Kritik geschätzt ...

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;
}

Wenn Sie vergleichen JSON Objekte, die Sie verwenden können, https://github.com/mirek/node -rus-diff

npm install rus-diff

Verbrauch:

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 } }

Wenn zwei Objekte voneinander verschieden sind, ein MongoDB kompatibel {$rename:{...}, $unset:{...}, $set:{...}} wie Objekt zurückgegeben wird.

ich vor dem gleichen Problem und deccided meine eigene Lösung zu schreiben. Aber weil ich mag auch Arrays mit Objekten und umgekehrt vergleichen, gestaltete ich eine generische Lösung. Ich beschloss, die Funktionen für den Prototyp hinzuzufügen, aber man kann sich leicht umschreiben Funktionen Eigenständig. Hier ist der Code:

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;
}

Dieser Algorithmus ist in zwei Teile geteilt; Die equals Funktion selbst und eine Funktion, um den numerischen Index einer Eigenschaft in einem Array / Objekt zu finden. Die Suchfunktion wird nur benötigt, weil IndexOf nur Zahlen und Strings findet und keine Objekte.

Man kann es so nennen:

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

Die Funktion liefert entweder wahr oder falsch, in diesem Fall wahr. Der Algorithmus als erlaubt den Vergleich zwischen sehr komplexen Objekten:

({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"]})

Das obere Beispiel wird true zurück, auch tho die Eigenschaften eine andere Ordnung haben. Ein kleines Detail, wo sie nach. Dieser Code prüft auch, ob die gleiche Art von zwei Variablen, so „3“ ist nicht das gleiche wie 3

Ich wollte nur meine Version von Objekten Vergleich beitragen Verwendung einiger es6 Funktionen. Es ist nicht eine Bestellung berücksichtigt werden. Nach der Konvertierung ich alle if / else ist ternäre haben kam mit folgenden:

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;

        }
    )
}

Es ist nützlich, um zwei Objekte zu betrachten gleich, wenn sie alle dieselben Werte für alle Eigenschaften und rekursiv für alle verschachtelten Objekten und Arrays. Ich halte auch die folgenden zwei Objekte gleich:

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

Auf ähnliche Weise kann Arrays „fehlende“ Elemente und nicht definierten Elemente.

: Ich würde diejenigen, die gleiche wie gut behandeln
var c = [1, 2];
var d = [1, 2, undefined];

Eine Funktion, die diese Definition der Gleichheit implementiert:

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;
}

Quellcode (einschließlich der Hilfsfunktionen, generalType und uniqueArray): Unit Test und Test Runner hier .

Ich mache die folgenden Annahmen mit dieser Funktion:

  1. Sie steuern die Objekte, die Sie vergleichen und Sie haben nur primitive Werte (dh. Nicht verschachtelte Objekte, Funktionen, usw.).
  2. Ihr Browser hat Unterstützung für Object.keys .

Dies sollte als eine Demonstration einer einfachen Strategie behandelt werden.

/**
 * 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;
}

Dies ist eine Ergänzung für alle die oben, keine Ersatz.Wenn Sie benötigen, um schnell flach-vergleichen von Objekten ohne die Notwendigkeit zu prüfen, extra rekursiven Fälle.Hier ist ein Schuss.

Dieser vergleicht für:1) gleiche Anzahl von eigenen Eigenschaften, 2), die Gleichheit der Namen von Tasten, 3) wenn bCompareValues == true, wird die Gleichheit der entsprechenden Eigenschaft Werte und Ihre Typen (triple-Gleichheit)

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;
}

Für Tasten für einfache Schlüssel / Wert-Paare Objektinstanzen zu vergleichen, die ich benutze:

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);
};

Sobald Schlüssel verglichen werden, eine einfache zusätzliche for..in Schleife ist genug.

Komplexität O (N * N) wobei N die Anzahl der Tasten ist.

Ich hoffe / Vermutung Objekte definiere ich nicht mehr als 1000 Eigenschaften besitzen ...

Ich weiß, das ist ein bisschen alt, aber ich möchte eine Lösung hinzuzufügen, die ich mit diesem Problem kam. Ich hatte ein Objekt, und ich wollte wissen, wann seine Daten geändert. „Etwas Ähnliches wie Object.observe“ und was ich tat, war:

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)
}

hier Dies kann einen anderen Satz von Arrays, die die Werte und Schlüssel vergleichen dupliziert und erstellen werden. Es ist sehr einfach, weil sie nun Arrays sind und werden wiederkommen falsch, wenn Objekte unterschiedliche Größen haben.

Ziehen von meiner persönlichen Bibliothek aus, die ich immer wieder für meine Arbeit verwenden. Die folgende Funktion eine milde rekursive tief gleich, die prüft nicht,

  • Klasse Gleichheit
  • Geerbte Werte
  • Werte strikte Gleichheit

Ich benutze dies vor allem zu prüfen, ob i gleich Antworten gegen verschiedene API-Implementierung bekommen. Wo Implementierung Differenz (wie String-vs-Nummer) und weitere Nullwerte, auftreten kann.

Die Umsetzung ist sehr einfach und kurz ist (wenn alle Kommentare abgezogen)

/** 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!");
	}
})();

Hier ist eine Version des stringify Trick, weniger tippen und arbeitet in vielen Fällen für trivial JSON Datenvergleiche.

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

I Spaghetti-Code Antworten zu sehen. Ohne irgendwelche Dritte Libs zu verwenden, ist dies sehr einfach.

Zunächst sortieren die beiden Objekte durch Schlüssel ihre Schlüsselnamen.

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)

Dann einfach eine Zeichenfolge verwenden, um sie zu vergleichen.

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

Für die von Ihnen mit NodeJS, gibt es eine bequeme Methode isDeepStrictEqual auf der nativen Util Bibliothek genannt, die dies erreichen können.

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top