Zasadniczo próbuję stworzyć obiekt z unikatowych obiektów, zbiór. Wpadłem na genialny pomysł, aby po prostu użyć obiektu JavaScript z obiektami jako nazwami właściwości. Jak na przykład,
set[obj] = true;
To działa do pewnego momentu. Działa świetnie z ciągami i liczbami, ale w przypadku innych obiektów wszystkie wydają się „mieszać” do tej samej wartości i mają dostęp do tej samej właściwości. Czy istnieje sposób, w jaki mogę wygenerować unikalną wartość skrótu dla obiektu? Jak to robią ciągi i liczby, czy mogę zmienić to samo zachowanie?
javascript
hash
set
hashcode
Boguś
źródło
źródło
JSON.stringify(obj)
lubobj.toSource()
może działać dla Ciebie w zależności od problemu i platformy docelowej.toSource
nie pracuj w Chrome btwOdpowiedzi:
Obiekty JavaScript mogą używać tylko łańcuchów jako kluczy (wszystko inne jest konwertowane na łańcuch).
Możesz, alternatywnie, utrzymywać tablicę, która indeksuje dane obiekty i używać jej ciągu indeksowego jako odniesienia do obiektu. Coś takiego:
Oczywiście jest to trochę rozwlekłe, ale możesz napisać kilka metod, które sobie z tym poradzą i uzyskać i ustawić wszystko, co chcesz.
Edytować:
To prowadzi do kolejnego interesującego punktu; możesz zdefiniować metodę toString na obiektach, które chcesz haszować, i która może utworzyć ich identyfikator skrótu.
źródło
Jeśli potrzebujesz funkcji hashCode (), takiej jak Java w JavaScript, to jest twoja:
Taki jest sposób implementacji w Javie (operator bitowy).
Zwróć uwagę, że hashCode może być dodatni i ujemny, i to normalne, zobacz HashCode podający wartości ujemne . Możesz więc rozważyć użycie
Math.abs()
razem z tą funkcją.źródło
char
jest słowem zastrzeżonym w JS i może powodować pewne problemy. Lepsza byłaby inna nazwa.pickOne["helloo".hashCode() % 20]
dla tablicypickOne
z 20 elementami. Otrzymałem,undefined
ponieważ kod skrótu jest ujemny, więc jest to przykład, w którym ktoś (ja) domyślnie założył dodatnie kody skrótu.Najłatwiej to zrobić, nadając każdemu obiektowi własną unikalną
toString
metodę:Miałem ten sam problem i to rozwiązało go doskonale dla mnie przy minimalnym zamieszaniu i było o wiele łatwiejsze niż ponowne zaimplementowanie jakiegoś tłustego stylu Java
Hashtable
i dodanieequals()
ihashCode()
do klas obiektów. Po prostu upewnij się, że nie wklejasz również ciągu znaków '<#MyObject: 12> do swojego hasha, bo spowoduje to wyczyszczenie wpisu dla wychodzącego obiektu o tym identyfikatorze.Teraz wszystkie moje skróty są całkowicie wyluzowane. Kilka dni temu właśnie zamieściłem na blogu wpis na ten temat .
źródło
equals()
ihashCode()
tak, że dwa równoważne obiekty mają tę samą wartość skrótu. Użycie powyższej metody oznacza, że każda instancjaMyObject
będzie miała unikalny ciąg, co oznacza, że będziesz musiał zachować odniesienie do tego obiektu, aby kiedykolwiek pobrać poprawną wartość z mapy. Posiadanie klucza jest bez znaczenia, ponieważ nie ma to nic wspólnego z wyjątkowością przedmiotu. PrzydatnatoString()
funkcja będzie musiała zostać zaimplementowana dla konkretnego typu obiektu, którego używasz jako klucza.toString
dla obiektów tak, aby bezpośrednio odwzorowywał relację równoważności, tak aby dwa obiekty tworzyły ten sam ciąg, jeśli są uważane za „równe”.toString()
aby umożliwić używanieObject
jakoSet
. Myślę, że źle zrozumiałem twoją odpowiedź jako próbę przedstawienia ogólnego rozwiązania, aby uniknąć pisaniatoString()
odpowiednikaequals()
lubhashCode()
na podstawie każdego przypadku.To, co opisałeś, jest objęte Harmony WeakMaps , część specyfikacji ECMAScript 6 (kolejna wersja JavaScript). To znaczy: zestaw, w którym klucze mogą być dowolne (w tym niezdefiniowane) i nie są wyliczalne.
Oznacza to, że niemożliwe jest uzyskanie odniesienia do wartości, jeśli nie masz bezpośredniego odniesienia do klucza (dowolnego obiektu!), Który jest z nią powiązany. Jest to ważne z wielu powodów związanych z implementacją silnika związanych z wydajnością i usuwaniem elementów bezużytecznych, ale jest również super fajne, ponieważ pozwala na nową semantykę, taką jak odwoływalne uprawnienia dostępu i przekazywanie danych bez ujawniania nadawcy danych.
Z MDN :
WeakMaps są dostępne w aktualnych przeglądarkach Firefox, Chrome i Edge. Są również obsługiwane w Node v7 i v6 z
--harmony-weak-maps
flagą.źródło
Map
?var m = new Map();m.set({},"abc"); console.log(m.get({}) //=>undefined
Działa tylko wtedy, gdy masz tę samą zmienną, do której pierwotnie się odwołałeś w poleceniu set. EGvar m = new Map();a={};m.set(a,"abc"); console.log(m.get(a) //=>undefined
Rozwiązanie, które wybrałem, jest podobne do rozwiązania Daniela, ale zamiast używać fabryki obiektów i przesłonić toString, jawnie dodaję hash do obiektu, gdy jest on po raz pierwszy żądany przez funkcję getHashCode. Trochę niechlujnie, ale lepiej na moje potrzeby :)
źródło
Object.defineProperty
pomocąenumerable
set tofalse
, aby nie zawiesić żadnychfor .. in
pętli.W mojej konkretnej sytuacji zależy mi tylko na równości obiektu, jeśli chodzi o klucze i prymitywne wartości. Rozwiązaniem, które zadziałało, było przekonwertowanie obiektu na jego reprezentację JSON i użycie tego jako skrótu. Istnieją ograniczenia, takie jak kolejność definicji kluczy, która może być niespójna; ale jak powiedziałem, to zadziałało, ponieważ wszystkie te obiekty były generowane w jednym miejscu.
źródło
Stworzyłam małą JavaScript moduł jakiś czas temu do hashcodes produkować dla strun, obiektów, tablic itp (I właśnie popełnił go do GitHub :))
Stosowanie:
źródło
var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.log(hash1, hash2);
będzie rejestrować2867874173
2867874173
Specyfikacja JavaScript definiuje dostęp do indeksowanej właściwości jako wykonanie konwersji toString na nazwie indeksu. Na przykład,
jest taki sam jak
Jest to konieczne, podobnie jak w JavaScript
jest taki sam jak
I tak, też mnie to smuci :-(
źródło
W ECMAScript 6 jest teraz opcja,
Set
która działa tak, jak chcesz: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SetJest już dostępny w najnowszej wersji Chrome, FF i IE11.
źródło
Źródła: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
możesz użyć symbolu Es6, aby stworzyć unikalny klucz i obiekt dostępu. Każda wartość symbolu zwrócona przez Symbol () jest unikalna. Wartość symbolu może służyć jako identyfikator właściwości obiektu; jest to jedyny cel tego typu danych.
źródło
Oto moje proste rozwiązanie, które zwraca unikalną liczbę całkowitą.
źródło
hashcode({a:1, b:2}) === hashcode({a:2, b:1})
i wielu innych konfliktów.Na podstawie tytułu możemy wygenerować silne hashe za pomocą js, można go użyć do wygenerowania unikalnego skrótu z obiektu, tablicy parametrów, ciągu lub cokolwiek innego.
Później do indeksowania pozwala to uniknąć ewentualnych błędów dopasowania, jednocześnie umożliwiając pobranie indeksu z parametrów (unikaj wyszukiwania / zapętlania obiektu itp.):
Powyższe wyjście w mojej przeglądarce powinno być dla Ciebie równe ( czy to naprawdę? ):
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string
źródło
Moje rozwiązanie wprowadza statyczną funkcję dla
Object
obiektu globalnego .Myślę, że jest to wygodniejsze w przypadku innych funkcji manipulowania obiektami w JavaScript.
źródło
Spróbuję pójść trochę głębiej niż inne odpowiedzi.
Nawet gdyby JS miał lepszą obsługę haszowania, nie magicznie haszowałby wszystkiego idealnie, w wielu przypadkach będziesz musiał zdefiniować własną funkcję haszującą. Na przykład Java ma dobrą obsługę mieszania, ale nadal musisz pomyśleć i trochę popracować.
Jeden problem dotyczy terminu hash / hashcode ... jest szyfrowanie kryptograficzne i haszowanie niekryptograficzne. Innym problemem jest to, że musisz zrozumieć, dlaczego haszowanie jest przydatne i jak działa.
Kiedy mówimy o haszowaniu w JavaScript lub Javie, przez większość czasu mówimy o haszowaniu niekryptograficznym, zwykle o haszowaniu dla haszowania / tablicy haszującej (chyba że pracujemy nad uwierzytelnianiem lub hasłami, które możesz wykonywać po stronie serwera za pomocą NodeJS. ..).
To zależy od tego, jakie masz dane i co chcesz osiągnąć.
Twoje dane mają naturalną „prostą” wyjątkowość:
Twoje dane mają naturalną wyjątkowość „złożoną”:
Nie masz pojęcia, jakie będą Twoje dane:
Nie ma magicznie wydajnej techniki haszowania nieznanych danych, w niektórych przypadkach jest to dość łatwe, w innych może być konieczne zastanowienie się dwa razy. Więc nawet jeśli JavaScript / ECMAScript dodaje więcej wsparcia, nie ma magicznego rozwiązania tego problemu.
W praktyce potrzebujesz dwóch rzeczy: wystarczającej unikalności, wystarczającej szybkości
Poza tym świetnie jest mieć: „kod hash jest równy, jeśli obiekty są równe”
źródło
Jeśli naprawdę chcesz ustawić zachowanie (idę przez znajomość języka Java), trudno będzie znaleźć rozwiązanie w JavaScript. Większość programistów zaleci unikalny klucz do reprezentowania każdego obiektu, ale jest to odmienne od zestawu, ponieważ można uzyskać dwa identyczne obiekty, każdy z unikalnym kluczem. Interfejs Java API sprawdza zduplikowane wartości, porównując wartości kodu skrótu, a nie kluczy, a ponieważ nie ma reprezentacji wartości kodu skrótu obiektów w JavaScript, wykonanie tego samego staje się prawie niemożliwe. Nawet biblioteka Prototype JS przyznaje się do tego niedociągnięcia, gdy mówi:
http://www.prototypejs.org/api/hash
źródło
Oprócz odpowiedzi bez powiek, oto funkcja, która zwraca powtarzalny, unikalny identyfikator dla dowolnego obiektu:
Jak widać, używa listy do wyszukiwania, która jest bardzo nieefektywna, jednak to najlepsze, co na razie znalazłem.
źródło
Jeśli chcesz używać obiektów jako kluczy, musisz nadpisać ich metodę toString, jak już wspomniano tutaj. Wszystkie użyte funkcje skrótu są w porządku, ale działają tylko dla tych samych obiektów, a nie dla równych obiektów.
Napisałem małą bibliotekę, która tworzy skróty z obiektów, których możesz łatwo użyć do tego celu. Obiekty mogą mieć nawet inną kolejność, skróty będą takie same. Wewnętrznie możesz użyć różnych typów dla swojego skrótu (djb2, md5, sha1, sha256, sha512, ripemd160).
Oto mały przykład z dokumentacji:
Pakiet może być używany zarówno w przeglądarce, jak iw Node-Js.
Repozytorium: https://bitbucket.org/tehrengruber/es-js-hash
źródło
Jeśli chcesz mieć unikalne wartości w obiekcie wyszukiwania, możesz zrobić coś takiego:
Tworzenie obiektu wyszukiwania
Konfigurowanie funkcji hashcode
Obiekt
Szyk
Inne rodzaje
Ostateczny wynik
{ 1337: true, 01132337: true, StackOverflow: true }
Zwróć uwagę, że
getHashCode
nie zwraca żadnej wartości, gdy obiekt lub tablica jest pustaJest to podobne do rozwiązania @ijmacd,
getHashCode
ale nie maJSON
zależności.źródło
Połączyłem odpowiedzi z bez powiek i KimKha.
Poniżej znajduje się usługa angularjs, która obsługuje liczby, ciągi znaków i obiekty.
Przykładowe zastosowanie:
Wynik
Wyjaśnienie
Jak widać, sercem usługi jest funkcja skrótu stworzona przez KimKha. Dodałem typy do łańcuchów, aby struktura obiektu również wpłynęła na ostateczną wartość skrótu. Klucze są haszowane, aby zapobiec kolizjom tablic | obiektów.
Porównywanie obiektów bez powiek służy do zapobiegania nieskończonej rekurencji przez obiekty odnoszące się do siebie.
Stosowanie
Utworzyłem tę usługę, aby mieć usługę błędów, do której można uzyskać dostęp za pomocą obiektów. Aby jedna usługa mogła zarejestrować błąd w danym obiekcie, a inna mogła określić, czy znaleziono jakieś błędy.
to znaczy
JsonValidation.js
UserOfData.js
To zwróci:
Podczas
To wróci
źródło
Po prostu użyj ukrytej tajnej właściwości z rozszerzeniem
defineProperty
enumerable: false
Działa bardzo szybko :
źródło