995 Stimmen

Wie bestimmt man die Gleichheit zweier JavaScript-Objekte?

Ein strikter Gleichheitsoperator sagt Ihnen, ob zwei Objekte Typen gleich sind. Gibt es jedoch eine Möglichkeit zu erkennen, 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 dieser Frage ähnlich, erfordert aber eine eher akademische Antwort. Das obige Szenario zeigt, warum es notwendig wäre, eine zu haben, und ich frage mich, ob es irgendeine gleichwertige Lösung .

5 Stimmen

Gehen Sie auch dieser Frage nach stackoverflow.com/q/1068834/1671639

55 Stimmen

Beachten Sie, dass auch in Java, a.hashCode() == b.hashCode() tut no bedeuten, dass a ist gleich b . Das ist eine notwendige, aber keine hinreichende Bedingung.

7 Stimmen

Wenn Sie Objekte in Ihrem Code vergleichen MÜSSEN, dann haben Sie Ihren Code wahrscheinlich falsch geschrieben. Die bessere Frage könnte lauten: "Wie kann ich diesen Code so schreiben, dass ich keine Objekte vergleichen muss?"

2voto

scipper Punkte 2596

Obwohl diese Frage hinreichend beantwortet ist, fehlt mir ein Ansatz: die toJSON Schnittstelle.

Normalerweise möchte man mit Objekten vergleichen, indem man sie in eine Zeichenkette einfügt, da dies der schnellste Weg ist. Aber manchmal wird der Vergleich als falsch angesehen, weil die Reihenfolge der Eigenschaften nicht stimmt.

const obj1 = {
  a: 1,
  b: 2,
  c: { 
    ca: 1,
    cb: 2
  }
}

const obj2 = {
  b: 2, // changed order with a
  a: 1,
  c: { 
    ca: 1,
    cb: 2
  }
}

JSON.stringify(obj1) === JSON.stringify(obj2) // false

Offensichtlich werden die Objekte als unterschiedlich betrachtet, da die Reihenfolge der Eigenschaften a y b unterschiedlich.

Um dieses Problem zu lösen, können Sie die toJSON Schnittstelle, und definieren Sie eine deterministische Ausgabe.

const obj1 = {
  a: 1,
  b: 2,
  c: { 
    ca: 1,
    cb: 2
  },
  toJSON() {
    return {
      a: this.a,
      b: this.b,
      c: { 
        ca: this.c.ca,
        cb: this.c.ca
      }
    }
  }
}

const obj2 = {
  b: 2,
  a: 1,
  c: { 
    ca: 1,
    cb: 2
  },
  toJSON() {
    return {
      a: this.a,
      b: this.b,
      c: { 
        ca: this.c.ca,
        cb: this.c.ca
      }
    }
  }
}

JSON.stringify(obj1) === JSON.stringify(obj2) // true

Et voila: die String-Darstellungen von obj1 y obj2 werden als gleichwertig betrachtet.

TIPP

Wenn Sie keinen Zugriff auf die direkte Erzeugung des Objekts haben, können Sie einfach die toJSON Funktion:

obj1.toJSON = function() {
  return {
    a: this.a,
    b: this.b,
    c: { 
      ca: this.c.ca,
      cb: this.c.ca
    }
  }
}

obj2.toJSON = function() {
  return {
    a: this.a,
    b: this.b,
    c: { 
      ca: this.c.ca,
      cb: this.c.ca
    }
  }
}

JSON.stringify(obj1) === JSON.stringify(obj2) // true

0 Stimmen

Das scheint nicht wirklich praktikabel zu sein, wenn nicht in trivialen Fällen. Stellen Sie sich vor, Sie haben ein Objekt mit vielen Eigenschaften. Auch löst es nicht das Problem der Gleichheit zwischen Arrays

2voto

Aldo Fregoso Punkte 21

Bei dieser Funktion gehe ich von den folgenden Annahmen aus:

  1. Sie kontrollieren die Objekte, die Sie vergleichen, und Sie haben nur primitive Werte (d.h. keine verschachtelten Objekte, Funktionen usw.).
  2. Ihr Browser bietet Unterstützung für Objekt.Schlüssel .

Dies sollte als Demonstration einer einfachen Strategie betrachtet 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;
}

2voto

Tolumide Punkte 848

Hier ist eine Lösung mit ES6+

// this comparison would not work for function and symbol comparisons
// this would only work best for compared objects that do not belong to same address in memory
// Returns true if there is no difference, and false otherwise

export const isObjSame = (obj1, obj2) => {
    if (typeof obj1 !== "object" && obj1 !== obj2) {
        return false;
    }

    if (typeof obj1 !== "object" && typeof obj2 !== "object" && obj1 === obj2) {
        return true;
    }

    if (typeof obj1 === "object" && typeof obj2 === "object") {
        if (Array.isArray(obj1) && Array.isArray(obj2)) {
            if (obj1.length === obj2.length) {
                if (obj1.length === 0) {
                    return true;
                }
                const firstElemType = typeof obj1[0];

                if (typeof firstElemType !== "object") {
                    const confirmSameType = currentType =>
                        typeof currentType === firstElemType;

                    const checkObjOne = obj1.every(confirmSameType);
                    const checkObjTwo = obj2.every(confirmSameType);

                    if (checkObjOne && checkObjTwo) {
                        // they are primitves, we can therefore sort before and compare by index
                        // use number sort
                        // use alphabet sort
                        // use regular sort
                        if (firstElemType === "string") {
                            obj1.sort((a, b) => a.localeCompare(b));
                            obj2.sort((a, b) => a.localeCompare(b));
                        }
                        obj1.sort((a, b) => a - b);
                        obj2.sort((a, b) => a - b);

                        let equal = true;

                        obj1.map((element, index) => {
                            if (!isObjSame(element, obj2[index])) {
                                equal = false;
                            }
                        });

                        return equal;
                    }

                    if (
                        (checkObjOne && !checkObjTwo) ||
                        (!checkObjOne && checkObjTwo)
                    ) {
                        return false;
                    }

                    if (!checkObjOne && !checkObjTwo) {
                        for (let i = 0; i <= obj1.length; i++) {
                            const compareIt = isObjSame(obj1[i], obj2[i]);
                            if (!compareIt) {
                                return false;
                            }
                        }

                        return true;
                    }

                    // if()
                }
                const newValue = isObjSame(obj1, obj2);
                return newValue;
            } else {
                return false;
            }
        }

        if (!Array.isArray(obj1) && !Array.isArray(obj2)) {
            let equal = true;
            if (obj1 && obj2) {
                const allKeys1 = Array.from(Object.keys(obj1));
                const allKeys2 = Array.from(Object.keys(obj2));

                if (allKeys1.length === allKeys2.length) {
                    allKeys1.sort((a, b) => a - b);
                    allKeys2.sort((a, b) => a - b);

                    allKeys1.map((key, index) => {
                        if (
                            key.toLowerCase() !== allKeys2[index].toLowerCase()
                        ) {
                            equal = false;
                            return;
                        }

                        const confirmEquality = isObjSame(obj1[key], obj2[key]);

                        if (!confirmEquality) {
                            equal = confirmEquality;
                            return;
                        }
                    });
                }
            }

            return equal;

            // return false;
        }
    }
};

2voto

Hefeust CORTES Punkte 101

Für den Vergleich von Schlüsseln für einfache Schlüssel/Wert-Paare verwende ich Objektinstanzen:

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 die Schlüssel verglichen sind, wird eine einfache zusätzliche for..in Schleife ist genug.

Die Komplexität ist O(N*N), wobei N die Anzahl der Schlüssel ist.

Ich hoffe/vermutet, dass die von mir definierten Objekte nicht mehr als 1000 Eigenschaften haben werden...

1voto

FOR_SCIENCE Punkte 106

In React können Sie Folgendes verwenden isEqual von 'react-fast-compare'. Diese Antwort ist wahrscheinlich nicht auf einfaches JavaScript anwendbar, kann aber nützlich sein, wenn Sie React verwenden.

console.log(isEqual({ hello: 'world' }, { hello: 'world' })) // returns true

Der schnellste Deep Equal Vergleich für React. Auch sehr schneller Allzweck-Tiefenvergleich. Großartig für React.memo und shouldComponentUpdate.

Weitere Informationen finden Sie hier: https://www.npmjs.com/package/react-fast-compare .

0 Stimmen

Und wenn Sie React nicht benutzen, verwenden Sie einfach das Paket 'react-fast-compare', das auf github.com/epoberezkin/fast-deep-equal

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X