Grundsätzlich versuche ich, ein Objekt aus eindeutigen Objekten, eine Menge, zu erstellen. Ich hatte die geniale Idee, nur ein JavaScript-Objekt mit Objekten für die Eigenschaftsnamen zu verwenden. Sowie,
set[obj] = true;
Dies funktioniert bis zu einem gewissen Punkt. Es funktioniert hervorragend mit Zeichenfolgen und Zahlen, aber mit anderen Objekten scheinen alle auf denselben Wert zu "hashen" und auf dieselbe Eigenschaft zuzugreifen. Gibt es eine Möglichkeit, einen eindeutigen Hashwert für ein Objekt zu generieren? Wie machen Strings und Zahlen das? Kann ich das gleiche Verhalten überschreiben?
javascript
hash
set
hashcode
Boog
quelle
quelle
JSON.stringify(obj)
oderobj.toSource()
kann je nach Problem und Zielplattform für Sie arbeiten.toSource
arbeiten nicht in Chrome übrigensAntworten:
JavaScript-Objekte können nur Zeichenfolgen als Schlüssel verwenden (alles andere wird in eine Zeichenfolge konvertiert).
Alternativ können Sie ein Array verwalten, das die betreffenden Objekte indiziert, und seine Indexzeichenfolge als Referenz auf das Objekt verwenden. Etwas wie das:
Natürlich ist es ein wenig ausführlich, aber Sie könnten ein paar Methoden schreiben, die damit umgehen und alles wohl oder übel bekommen und einstellen.
Bearbeiten:
Dies bringt einen weiteren interessanten Punkt auf; Sie können eine toString-Methode für die Objekte definieren, die Sie hashen möchten, und diese können ihre Hash-ID bilden.
quelle
Wenn Sie eine hashCode () -Funktion wie die von Java in JavaScript möchten, gehört diese Ihnen:
Dies ist die Art der Implementierung in Java (bitweiser Operator).
Bitte beachten Sie, dass hashCode positiv und negativ sein kann, und das ist normal. Siehe HashCode mit negativen Werten . Sie können also in Betracht ziehen,
Math.abs()
diese Funktion zusammen mit dieser Funktion zu verwenden.quelle
char
ist ein reserviertes Wort in JS und kann einige Probleme verursachen. Ein anderer Name wäre besser.pickOne["helloo".hashCode() % 20]
für ein ArraypickOne
mit 20 Elementen zu tun . Ich habe bekommen,undefined
weil der Hash-Code negativ ist, also ist dies ein Beispiel, in dem jemand (ich) implizit positive Hash-Codes angenommen hat.Der einfachste Weg, dies zu tun, besteht darin, jedem Ihrer Objekte eine eigene
toString
Methode zuzuweisen:Ich hatte das gleiche Problem und dies löste es perfekt für mich mit minimalem Aufwand und war viel einfacher als das erneute Implementieren eines fetten Java-Stils
Hashtable
und das Hinzufügenequals()
und HinzufügenhashCode()
zu Ihren Objektklassen. Stellen Sie einfach sicher, dass Sie nicht auch eine Zeichenfolge '<#MyObject: 12> in Ihren Hash einfügen, da sonst der Eintrag für Ihr vorhandenes Objekt mit dieser ID gelöscht wird.Jetzt sind alle meine Hashes total kalt. Ich habe vor ein paar Tagen auch einen Blogeintrag zu diesem Thema gepostet .
quelle
equals()
undhashCode()
so haben zwei äquivalente Objekte den gleichen Hashwert. Die Verwendung der obigen Methode bedeutet, dass jede Instanz vonMyObject
eine eindeutige Zeichenfolge hat. Dies bedeutet, dass Sie einen Verweis auf dieses Objekt behalten müssen, um jemals den richtigen Wert aus der Karte abzurufen. Einen Schlüssel zu haben ist bedeutungslos, weil er nichts mit der Einzigartigkeit eines Objekts zu tun hat.toString()
Für den bestimmten Objekttyp, den Sie als Schlüssel verwenden, muss eine nützliche Funktion implementiert werden.toString
für die Objekte so implementieren, dass es direkt einer Äquivalenzbeziehung zugeordnet wird, sodass zwei Objekte dieselbe Zeichenfolge erstellen, wenn sie als "gleich" betrachtet werden.toString()
, um eineObject
als zu verwendenSet
. Ich glaube, ich habe Ihre Antwort als Versuch missverstanden, eine generische Lösung bereitzustellen, um zu vermeiden, dass eintoString()
Äquivalent vonequals()
oderhashCode()
von Fall zu Fall geschrieben wird.Was Sie beschrieben haben, wird von Harmony WeakMaps abgedeckt , einem Teil der ECMAScript 6- Spezifikation (nächste Version von JavaScript). Das heißt: eine Menge, in der die Schlüssel alles sein können (einschließlich undefinierter) und nicht aufzählbar sind.
Dies bedeutet, dass es unmöglich ist, einen Verweis auf einen Wert zu erhalten, es sei denn, Sie haben einen direkten Verweis auf den Schlüssel (ein beliebiges Objekt!), Der darauf verweist. Es ist wichtig für eine Reihe von Gründen für die Engine-Implementierung in Bezug auf Effizienz und Speicherbereinigung, aber es ist auch super cool, da es neue Semantiken wie widerrufbare Zugriffsberechtigungen und das Übergeben von Daten ermöglicht, ohne den Datensender offenzulegen.
Von MDN :
WeakMaps sind in den aktuellen Versionen Firefox, Chrome und Edge verfügbar. Sie werden auch in Node v7 und in v6 mit dem
--harmony-weak-maps
Flag unterstützt.quelle
Map
?var m = new Map();m.set({},"abc"); console.log(m.get({}) //=>undefined
Es funktioniert nur, wenn Sie dieselbe Variable haben, auf die Sie ursprünglich im Befehl set verwiesen haben. EGvar m = new Map();a={};m.set(a,"abc"); console.log(m.get(a) //=>undefined
Die von mir gewählte Lösung ähnelt der von Daniel, aber anstatt eine Objektfactory zu verwenden und den toString zu überschreiben, füge ich dem Objekt den Hash explizit hinzu, wenn er zum ersten Mal über eine getHashCode-Funktion angefordert wird. Ein bisschen chaotisch, aber besser für meine Bedürfnisse :)
quelle
Object.defineProperty
mitenumerable
set auf zu setzenfalse
, damit Sie keinefor .. in
Schleifen zum Absturz bringen .Für meine spezifische Situation ist mir die Gleichheit des Objekts nur in Bezug auf Schlüssel und primitive Werte wichtig. Die Lösung, die für mich funktioniert hat, bestand darin, das Objekt in seine JSON-Darstellung zu konvertieren und dieses als Hash zu verwenden. Es gibt Einschränkungen wie die Reihenfolge der Schlüsseldefinition, die möglicherweise inkonsistent ist. aber wie gesagt, es hat bei mir funktioniert, weil diese Objekte alle an einem Ort erzeugt wurden.
quelle
Ich habe vor einiger Zeit ein kleines JavaScript-Modul zusammengestellt, um Hashcodes für Strings, Objekte, Arrays usw. zu erstellen (ich habe es gerade an GitHub übergeben :))
Verwendung:
quelle
var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.log(hash1, hash2);
protokollieren2867874173
2867874173
In der JavaScript-Spezifikation wird der Zugriff auf indizierte Eigenschaften so definiert, dass eine toString-Konvertierung für den Indexnamen durchgeführt wird. Beispielsweise,
ist das gleiche wie
Dies ist wie in JavaScript erforderlich
ist das gleiche wie
Und ja, es macht mich auch traurig :-(
quelle
In ECMAScript 6 gibt es jetzt eine
Set
, die so funktioniert, wie Sie es möchten: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SetEs ist bereits in den neuesten Versionen von Chrome, FF und IE11 verfügbar.
quelle
Referenz: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
Mit dem Es6-Symbol können Sie einen eindeutigen Schlüssel erstellen und auf ein Objekt zugreifen. Jeder von Symbol () zurückgegebene Symbolwert ist eindeutig. Ein Symbolwert kann als Bezeichner für Objekteigenschaften verwendet werden. Dies ist der einzige Zweck des Datentyps.
quelle
Hier ist meine einfache Lösung, die eine eindeutige Ganzzahl zurückgibt.
quelle
hashcode({a:1, b:2}) === hashcode({a:2, b:1})
und vieler anderer Konflikte.Basierend auf dem Titel können wir mit js starke Hashes generieren. Es kann verwendet werden, um einen eindeutigen Hash aus einem Objekt, einem Array von Parametern, einer Zeichenfolge oder was auch immer zu generieren.
Vermeiden Sie später für die Indizierung mögliche Übereinstimmungsfehler, während Sie gleichzeitig einen Index aus den Parametern abrufen können (vermeiden Sie das Suchen / Schleifen des Objekts usw.):
Die obige Ausgabe in meinem Browser sollte auch für Sie gleich sein ( Ist es wirklich? ):
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string
quelle
Meine Lösung führt eine statische Funktion für das globale
Object
Objekt ein.Ich denke, dass dies mit anderen Objektmanipulationsfunktionen in JavaScript bequemer ist.
quelle
Ich werde versuchen, etwas tiefer zu gehen als andere Antworten.
Selbst wenn JS eine bessere Hashing-Unterstützung hätte, würde es nicht alles auf magische Weise perfekt hashen. In vielen Fällen müssen Sie Ihre eigene Hash-Funktion definieren. Zum Beispiel hat Java eine gute Hashing-Unterstützung, aber Sie müssen noch nachdenken und etwas arbeiten.
Ein Problem ist mit dem Begriff Hash / Hashcode ... es gibt kryptografisches Hashing und nicht kryptografisches Hashing. Das andere Problem ist, dass Sie verstehen müssen, warum Hashing nützlich ist und wie es funktioniert.
Wenn wir die meiste Zeit über Hashing in JavaScript oder Java sprechen, sprechen wir über nicht kryptografisches Hashing, normalerweise über Hashing für Hashmap / Hashtable (es sei denn, wir arbeiten an Authentifizierung oder Passwörtern, die Sie möglicherweise serverseitig mit NodeJS durchführen. ..).
Es hängt davon ab, über welche Daten Sie verfügen und was Sie erreichen möchten.
Ihre Daten haben eine natürliche "einfache" Einzigartigkeit:
Ihre Daten haben eine natürliche "zusammengesetzte" Einzigartigkeit:
Sie haben keine Ahnung, wie Ihre Daten aussehen werden:
Es gibt keine magisch effiziente Hashing-Technik für unbekannte Daten. In einigen Fällen ist dies recht einfach, in anderen Fällen müssen Sie möglicherweise zweimal überlegen. Selbst wenn JavaScript / ECMAScript mehr Unterstützung bietet, gibt es keine magische Sprachlösung für dieses Problem.
In der Praxis braucht man zwei Dinge: genug Einzigartigkeit, genug Geschwindigkeit
Darüber hinaus ist es toll zu haben: "Hashcode gleich, wenn Objekte gleich sind"
quelle
Wenn Sie wirklich ein festgelegtes Verhalten wünschen (ich gehe von Java-Kenntnissen aus), wird es Ihnen schwer fallen, eine Lösung in JavaScript zu finden. Die meisten Entwickler empfehlen einen eindeutigen Schlüssel, um jedes Objekt darzustellen. Dies ist jedoch anders als bei set, da Sie zwei identische Objekte mit jeweils einem eindeutigen Schlüssel erhalten können. Die Java-API sucht nach doppelten Werten, indem sie Hash-Code-Werte und keine Schlüssel vergleicht. Da Objekte in JavaScript keine Hash-Code-Wertdarstellung enthalten, ist es fast unmöglich, dasselbe zu tun. Sogar die Prototype JS-Bibliothek gibt dieses Manko zu, wenn es heißt:
http://www.prototypejs.org/api/hash
quelle
Zusätzlich zur Antwort der Augenlidlosigkeit gibt es hier eine Funktion, die eine reproduzierbare, eindeutige ID für jedes Objekt zurückgibt:
Wie Sie sehen können, wird eine Liste für die Suche verwendet, die sehr ineffizient ist. Dies ist jedoch die beste, die ich derzeit finden konnte.
quelle
Wenn Sie Objekte als Schlüssel verwenden möchten, müssen Sie deren toString-Methode überschreiben, wie einige hier bereits erwähnt haben. Die verwendeten Hash-Funktionen sind alle in Ordnung, funktionieren jedoch nur für dieselben Objekte, nicht für gleiche Objekte.
Ich habe eine kleine Bibliothek geschrieben, die Hashes aus Objekten erstellt, die Sie leicht für diesen Zweck verwenden können. Die Objekte können sogar eine andere Reihenfolge haben, die Hashes sind gleich. Intern können Sie verschiedene Typen für Ihren Hash verwenden (djb2, md5, sha1, sha256, sha512, ripemd160).
Hier ist ein kleines Beispiel aus der Dokumentation:
Das Paket kann entweder im Browser und in Node-Js verwendet werden.
Repository: https://bitbucket.org/tehrengruber/es-js-hash
quelle
Wenn Sie eindeutige Werte in einem Suchobjekt haben möchten, können Sie Folgendes tun:
Erstellen eines Suchobjekts
Einrichten der Hashcode-Funktion
Objekt
Array
Andere Arten
Endergebnis
{ 1337: true, 01132337: true, StackOverflow: true }
Beachten Sie, dass
getHashCode
kein Wert zurückgegeben wird, wenn das Objekt oder Array leer istDies ähnelt der @ ijmacd-Lösung, hat jedoch nur
getHashCode
keineJSON
Abhängigkeit.quelle
Ich kombinierte die Antworten von Augenlidlosigkeit und KimKha.
Das Folgende ist ein AngularJS-Dienst, der Zahlen, Zeichenfolgen und Objekte unterstützt.
Anwendungsbeispiel:
Ausgabe
Erläuterung
Wie Sie sehen können, ist das Herzstück des Dienstes die von KimKha erstellte Hash-Funktion. Ich habe den Zeichenfolgen Typen hinzugefügt, damit sich die Struktur des Objekts auch auf den endgültigen Hash-Wert auswirkt. Die Schlüssel werden gehasht, um Kollisionen zwischen Array und Objekt zu verhindern.
Der Objektvergleich ohne Augenlid wird verwendet, um eine unendliche Rekursion durch selbstreferenzierende Objekte zu verhindern.
Verwendung
Ich habe diesen Dienst erstellt, damit ich einen Fehlerdienst haben kann, auf den mit Objekten zugegriffen wird. Damit ein Dienst einen Fehler mit einem bestimmten Objekt registrieren kann und ein anderer feststellen kann, ob Fehler gefunden wurden.
dh
JsonValidation.js
UserOfData.js
Dies würde zurückkehren:
Während
Dies würde zurückkehren
quelle
Verwenden Sie einfach versteckte geheime Eigenschaft mit dem
defineProperty
enumerable: false
Es funktioniert sehr schnell :
quelle