8. April 2014 | 6 Comments Nachdem ich letzte und vorletzte Woche auf Javascript und this eingegangen bin, möchte ich diese Woche darauf eingehen wie wir in Javascript Objekte vergleichen können… Oder eher: Warum das gar nicht so einfach ist! Vor kurzem bin ich über eine interessanten Blog-Eintrag auf designpepper.com gestoßen zum Thema „Objektgleichheit in JavaScript“. Von dort habe ich mir übrigens auch die Code-Snippets geliehen 😉 Vergleichsoperatoren sind nicht genug Bevor jemand auf die Idee kommt mit == oder === zu arbeiten: Das wird nicht ausreichen: // Simple equality. var jangoFett = { occupation: "Bounty Hunter", genetics: "superb" }; var bobaFett = { occupation: "Bounty Hunter", genetics: "superb" }; console.log(bobaFett === jangoFett); // Returns false console.log(bobaFett == jangoFett); // Still returns false Die Ursache, wieso diese Vergleiche fehlschlagen, liegt daran das Javascript verschiedene Typen unterschiedlich miteinander vergleicht. Bei primitiven Typen wie Strings und Nummern werden die Inhalte miteinander verglichen – Andere Typen wie Arrays, einfache- und Date-Objekte werden anhand ihrer Referenz verglichen… Da die beiden Objekte unterschiedliche Referenzen beherbergen schlägt der Vergleich fehl! Hier ein weiteres Beispiel von designpepper.com: var jangoFett = { occupation: "Bounty Hunter", genetics: "superb" }; var bobaFett = { occupation: "Bounty Hunter", genetics: "superb" }; var callMeJango = jangoFett; console.log(bobaFett === jangoFett); // Returns false console.log(callMeJango === jangoFett); // Returns true Hier verwenden callMeJango und jangoFett auf die gleiche Referenz – daher sind die Objekte (für Javascript) identisch. Eine Funktion muss her! Falls euch die Javascript-interne Prüfung nicht genügt und ihr lieber Inhalte miteinander vergleicht kommt ihr an einer eigenen Funktion nicht vorbei. Diese könnte folgendermaßen aussehen (erneut von designpepper.com): function isEquivalent(a, b) { // Create arrays of property names var aProps = Object.getOwnPropertyNames(a); var bProps = Object.getOwnPropertyNames(b); // If number of properties is different, // objects are not equivalent if (aProps.length != bProps.length) { return false; } for (var i = 0; i < aProps.length; i++) { var propName = aProps[i]; // If values of same property are not equal, // objects are not equivalent if (a[propName] !== b[propName]) { return false; } } // If we made it this far, objects // are considered equivalent return true; } console.log(isEquivalent(bobaFett, jangoFett)); // Returns true! Diese Funktion ist relativ einfach aufgebaut, ich möchte von oben nach unten durchgehen: Zuerst werden die Anzahl der Attribute miteinander verglichen. Stimmen diese nicht überein, sind die Objekte definitiv unterschiedlich Als nächstes werden die Attribute durchlaufen und auf den gleichen Inhalt geprüft - Unterscheidet sich z.B. jangoFett['occupation'] von bobaFett['occupation'] wird sofort abgebrochen! Sollte keine der Vergleiche fehlschlagen handelt es sich um ein identisches Objekt! Aber Achtung! Diese Funktion wird zwar mit einfachen Objekte funktionieren, doch komplexe(re) Objekte werden nicht korrekt überprüft werden... Stellt euch folgende Situationen vor: Was, wenn eines der Attribute ein Objekt beinhaltet? Was, wenn eines der Attribute NaN beinhaltet? Dieser Wert wird von Javascript nie als gleich angesehen (NaN === NaN ergibt false!) Was, wenn Objekt a ein Attribut mit dem Wert undefined hat, während b dieses Attribut nicht hat (was intern mit undefined übereinstimmt) ? Was kann ich also tun? Die erste Möglichkeit wäre die Funktion von oben einfach zu erweitern... Je nachdem, was für weitere Abfragen ihr benötigt! Die zweite Möglichkeit wäre eine Bibliothek zu benutzen. Eine relativ gute Funktion zum checken auf Gleichheit gibt es in Underscore.js, diese geht über knapp 90 Zeilen und kann sich bei bedarf selbst aufrufen (Rekursive Funktion). Lo-Dash bietet eine ähnliche Funktion an - diese geht allerdings über 160 Zeilen und arbeitet ebenfalls rekursiv. Habt ihr vielleicht noch weitere Tipps um "gleiche" Objekte miteinander zu vergleichen oder kennt einige Stolperfallen? Schreibt es in die Kommentare! Damit verabschiede ich mich für diese Woche und wünsche euch eine angenehme und sonnige Rest-Woche! Bis dahin wünsche ich euch Happy Coding!
Hi, erst mal klasse Lösung! Wäre es nicht einfacher wenn man die Überprüfung so machen würde? console.log(bobaFett.toString() === jangoFett.toString()); Gruß Christoph Antworten
Hallo ChristophJP, vielen Dank für dein Kommentar – auf die „toString()“ Methode bin ich hier tatsächlich gar nicht eingegangen. Führt man „bobaFett.toString()“ aus, erhält man als Ergebnis den String „[object Object]“ – das gleiche Resultat bekommt man aber bei allen anderen Objekten auch, wie z.B. bei: var x = {}; x.toString(); In Javascript gibt es leider keine einfache Funktionen, wie man sie aus PHP kennt (wie etwa get_class). Viele Grüße Leo Antworten
Hi Leo, Ich verwende die .toString() Methode für das vergleichen von Date Objekten und hatte nicht in Erwägung gezogen das, das natürlich bei Normalen Objekten nicht funktionieren kann. Gruß Christoph Antworten
Hi, man kann evtl. noch mit JSON arbeiten. JSON.stringify(obj) … und dann die Strings vergleichen. Grüße Antworten
Hallo Daniel, das ist richtig, die Funktion JSON.stringify(<obj>); dürfte in den meisten Fälle ausreichen! Wenn man allerdings Funktionen oder Referenzen innerhalb der Objekte hat werden diese herausgeworfen bzw. in den statischen String übernommen. Viele Grüße Leo Antworten