JavaScript'te herhangi bir karma kod işlevi var mı?


150

Temel olarak, bir dizi benzersiz nesnelerin bir nesne oluşturmaya çalışıyorum. Sadece özellik adları için nesnelerle bir JavaScript nesnesi kullanarak parlak bir fikir vardı. Gibi,

set[obj] = true;

Bu, bir noktaya kadar çalışır. Dize ve sayılarla harika çalışıyor, ancak diğer nesnelerle, hepsi aynı değere "hash" ediyor ve aynı özelliğe erişiyor. Bir nesne için benzersiz bir karma değer üretmenin bir yolu var mı? Dizeleri ve sayıları nasıl yapar, aynı davranışı geçersiz kılabilir miyim?


32
Nesnelerin hepsinin aynı değere 'hash' olmasının nedeni, toString yöntemlerini geçersiz kılmadığınızdır. Anahtarların dize olması gerektiğinden, geçerli bir anahtar elde etmek için toString yöntemi otomatik olarak çağrılır, böylece tüm nesneleriniz aynı varsayılan dizeye dönüştürülür: "[object Object]".
alanning

4
JSON.stringify(obj)veya obj.toSource()soruna ve hedef platforma bağlı olarak sizin için çalışabilir.
AnnanFay

4
@Annan JSON.stringify (obj) kelimenin tam anlamıyla (bütün) nesneyi bir dizeye dönüştürür. Yani temelde nesneyi kendi üzerine kopyalarsınız. Bu anlamsız, alan israfı ve optimal değil.
Metalstorm

1
@Metalstorm Doğru, bu yüzden probleminizin ne olduğuna bağlı. Bu soruyu google aracılığıyla bulduğumda son çözüm nesneler için toSource () 'u çağırıyordu. Başka bir yöntem, sadece kaynakta geleneksel bir karma kullanmak olacaktır.
AnnanFay

@Annan, toSourceChrome
btw'de

Yanıtlar:


35

JavaScript nesneleri dizeleri yalnızca anahtar olarak kullanabilir (başka her şey dizeye dönüştürülür).

Alternatif olarak, söz konusu nesneleri dizine ekleyen bir diziyi koruyabilir ve dizin dizesini nesneye başvuru olarak kullanabilirsiniz. Bunun gibi bir şey:

var ObjectReference = [];
ObjectReference.push(obj);

set['ObjectReference.' + ObjectReference.indexOf(obj)] = true;

Açıkçası biraz ayrıntılı, ama bunu ele almak ve tüm willy nilly almak ve ayarlamak birkaç yöntem yazabilirsiniz.

Düzenle:

Tahmininiz gerçek - bu JavaScript'te tanımlanmış davranıştır - özellikle bir toString dönüşümü gerçekleşir, bu da özellik adı olarak kullanılacak nesne üzerinde kendi toString işlevinizi tanımlayabileceğiniz anlamına gelir. - olliej

Bu da ilginç bir nokta daha getiriyor; karma yapmak istediğiniz nesnelerde bir toString yöntemi tanımlayabilirsiniz ve bu bunların karma tanımlayıcısını oluşturabilir.


başka bir seçenek, her nesneye karma olduğu gibi rastgele bir değer vermek olabilir - belki rastgele bir sayı + toplam keneler - daha sonra nesneyi diziye eklemek / diziden kaldırmak için bir dizi fonksiyona sahip olmaktır.
Sugendran

4
Aynı nesneyi iki kez eklerseniz bu başarısız olur. Farklı olduğunu düşünecek.
Daniel X Moore

"Aynı nesneyi iki kez eklerseniz bu başarısız olur. Farklı olduğunu düşünür." İyi bir nokta. Bir çözüm, yinelenen bir denetimi push () öğesine bağlayarak Array'ı ObjectReference için alt sınıflara ayırmak olabilir. Şimdi bu çözümü düzenlemek için zamanım yok ama umarım daha sonra hatırlayacağım.
göz kapaksızlığı

8
Bu çözümü seviyorum, çünkü nesnede herhangi bir ek özelliğe ihtiyaç duymaz. Ama temiz bir çöp toplayıcıya sahip olmaya çalışırsanız sorun oluyor. Yaklaşımınızda nesneyi kaydeder, ancak diğer referanslar zaten silinmiş demektir. Bu, daha büyük uygulamalarda sorunlara yol açabilir.
Johnny

35
Nesneleri her adlandırdığınızda, bir dizinin doğrusal taramasına ihtiyacınız varsa, nesnelerin hash edilmesinin anlamı nedir?
2014 tarihinde Bordaigorl

57

JavaScript'teki Java'lar gibi bir hashCode () işlevi istiyorsanız, bu sizin:

String.prototype.hashCode = function(){
    var hash = 0;
    for (var i = 0; i < this.length; i++) {
        var character = this.charCodeAt(i);
        hash = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

Java (bitsel operatör) uygulama yolu budur.

HashCode'un pozitif ve negatif olabileceğini lütfen unutmayın ve bu normaldir, Negatif değerler veren HashCode'a bakın . Bu nedenle, Math.abs()bu işlevle birlikte kullanmayı düşünebilirsiniz .


5
Bu mükemmel değil, -hash oluşturur
qodeninja

2
@KimKha JS'de charayrılmış sözcüktür ve bazı sorunlara neden olabilir. Başka bir isim daha iyi olurdu.
szeryf

16
@ qodeninja kim diyor? İlk defa böyle bir iddia duydum. Bazı kaynaklara bağlantı verebilir misiniz? Hashler genellikle sabit boyutlu tamsayı aritmetik ve bit işlemleri kullanılarak hesaplanır, bu nedenle pozitif veya negatif sonuçlar elde edilmesi beklenen bir şeydir.
szeryf

7
Seçici, ama ... "if (this.length == 0) karma döndürürse;" gereksizdir :) Ve kişisel olarak "karakter" i "kod" olarak değiştirir.
Metalstorm

10
@ qodeninja ve @szeryf: nasıl kullandığınıza dikkat etmelisiniz. Örneğin, 20 elemanlı pickOne["helloo".hashCode() % 20]bir dizi için yapmaya çalıştım pickOne. undefinedKarma kodu negatif olduğu için aldım , bu yüzden bu birisinin (ben) örtük olarak pozitif karma kodları aldığı bir örnektir.
Jim Pivarski

31

Bunu yapmanın en kolay yolu, nesnelerinizin her birine kendi benzersiz toStringyöntemini vermektir :

(function() {
    var id = 0;

    /*global MyObject */
    MyObject = function() {
        this.objectId = '<#MyObject:' + (id++) + '>';
        this.toString= function() {
            return this.objectId;
        };
    };
})();

Aynı sorunu yaşadım ve bu benim için en az yaygara ile mükemmel bir şekilde çözdü ve bazı yağlı Java stilini yeniden uygulamak Hashtableve ekleme equals()vehashCode() nesne sınıflarınıza . Sadece '<#MyObject: 12> dizesini karma değerine yapıştırmadığınızdan emin olun, aksi takdirde bu kimliğe sahip çıkış nesnenizin girişi silinir.

Şimdi tüm hashlarım tamamen ürpertici. Ayrıca birkaç gün önce bu konuyla ilgili bir blog yazısı yayınladım .


28
Ama bu bütün noktayı kaçırıyor. Java sahiptir equals()ve hashCode()böylece iki eşdeğer nesneleri aynı karma değerine sahiptir. Yukarıdaki yöntemi kullanmak, her bir örneğinin MyObjectbenzersiz bir dizeye sahip olacağı anlamına gelir; yani, haritadan doğru değeri almak için o nesneye bir referans tutmanız gerekir. Bir anahtarın olması anlamsızdır, çünkü bir nesnenin benzersizliğiyle ilgisi yoktur. toString()Anahtar olarak kullandığınız belirli bir nesne türü için yararlı bir işlevin uygulanması gerekir.
sethro

@sethro toString, nesneler için doğrudan bir eşdeğerlik ilişkisiyle eşleşecek şekilde uygulayabilir, böylece iki nesne "eşit" olarak kabul edildiğinde aynı dizeyi oluşturur.
Daniel X Moore

3
Doğru ve olması yalnızca kullanılacak doğru yolu toString()bir kullanmasına izin vermek Objectbir şekilde Set. Sanırım cevabınızı, toString()eşdeğeri equals()veya hashCode()duruma göre yazmamak için genel bir çözüm sunmaya çalışırken yanlış anladım .
sethro

3
Dowvoted. Bu bir
karma kod

5
@Metalstorm, soru "gerçek" bir hashcode hakkında değil, bir nesneyi JavaScript'te bir küme olarak nasıl başarılı bir şekilde kullanacağını soruyordu.
Daniel X Moore

20

Açıkladığınız şey ECMAScript 6 belirtiminin (JavaScript'in sonraki sürümü) bir parçası olan Harmony WeakMaps tarafından kapsanmaktadır . Yani, anahtarların herhangi bir şey olabileceği (tanımsız dahil) ve numaralandırılamayan bir set.

Bu, değere bağlantı veren anahtara (herhangi bir nesne!) Doğrudan başvurunuz olmadıkça bir değere başvuru yapmanın imkansız olduğu anlamına gelir. Verimlilik ve çöp toplama ile ilgili bir dizi motor uygulama nedeni için önemlidir, ancak aynı zamanda, iptal edilebilir erişim izinleri ve veri göndereni göstermeden veri geçirme gibi yeni semantiklere izin vermesi de çok iyidir.

Gönderen MDN'yi :

var wm1 = new WeakMap(),
    wm2 = new WeakMap();
var o1 = {},
    o2 = function(){},
    o3 = window;

wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // A value can be anything, including an object or a function.
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // Keys and values can be any objects. Even WeakMaps!

wm1.get(o2); // "azerty"
wm2.get(o2); // Undefined, because there is no value for o2 on wm2.
wm2.get(o3); // Undefined, because that is the set value.

wm1.has(o2); // True
wm2.has(o2); // False
wm2.has(o3); // True (even if the value itself is 'undefined').

wm1.has(o1);   // True
wm1.delete(o1);
wm1.has(o1);   // False

WeakMaps, mevcut Firefox, Chrome ve Edge'de mevcuttur. Ayrıca Düğüm v7'de ve v6'da --harmony-weak-mapsbayrakla desteklenirler.


1
Bunlar ve arasındaki fark nedir Map?
smac89

@ smac89 WeakMap'in sınırlamaları vardır: 1) Yalnızca anahtar olarak nesne alır 2) Boyut özelliği yok 3) Yineleyici veya forEach yöntemi yok 4) Net bir yöntem yok. Anahtar nesnedir - bu nedenle nesne bellekten silindiğinde - bu nesneye bağlı WeakMap'ten gelen veriler de silinir. Yalnızca nesne varken olması gereken bilgileri saklamak istediğimizde çok kullanışlıdır. WeakMap'in sadece yöntemleri vardır: ayarlamak, yazmak ve silmek için silmek, okumak için vardır
Ekaterina Tokareva

Bu tam olarak doğru şekilde çalışmaz ... var m = new Map();m.set({},"abc"); console.log(m.get({}) //=>undefinedSadece set komutunda başlangıçta başvurduğunuz değişkene sahipseniz çalışır. EGvar m = new Map();a={};m.set(a,"abc"); console.log(m.get(a) //=>undefined
Sancarn

1
@Sancarn Aynı değişken olması gerekmiyor, ancak aynı nesneyi göstermeleri gerekiyor. İlk örneğinizde iki farklı nesneniz var, aynı görünüyorlar, ancak farklı bir adresleri var.
Svish

1
@Vish iyi nokta! Şimdi biliyorum, o zamanlar hiç yapmamış olabilirim :)
Sancarn

19

Seçtiğim çözüm Daniel'inkine benzer, ancak bir nesne fabrikası kullanmak ve toString'i geçersiz kılmak yerine, ilk olarak getHashCode işleviyle istendiğinde hash nesnesine açıkça eklerim. Biraz dağınık, ama ihtiyaçlarım için daha iyi :)

Function.prototype.getHashCode = (function(id) {
    return function() {
        if (!this.hashCode) {
            this.hashCode = '<hash|#' + (id++) + '>';
        }
        return this.hashCode;
    }
}(0));

7
Bu şekilde gitmek istiyorsanız, hashCode'u set Object.definePropertyile üzerinden ayarlamak çok daha iyidir , böylece herhangi bir döngüyü kilitlemezsiniz. enumerablefalsefor .. in
Sebastian Nowak

14

Özel durumum için sadece anahtarlar ve ilkel değerler kadar nesnenin eşitliğini önemsiyorum. Benim için çalışan çözüm, nesneyi JSON temsiline dönüştürmek ve bunu karma olarak kullanmaktı. Anahtar tanım sırasının potansiyel olarak tutarsız olması gibi sınırlamalar vardır; ama dediğim gibi benim için çalıştı çünkü bu nesnelerin hepsi tek bir yerde üretiliyordu.

var hashtable = {};

var myObject = {a:0,b:1,c:2};

var hash = JSON.stringify(myObject);
// '{"a":0,"b":1,"c":2}'

hashtable[hash] = myObject;
// {
//   '{"a":0,"b":1,"c":2}': myObject
// }

10

Dizeler, nesneler, diziler vb. İçin karma kodlar üretmek üzere bir süre önce küçük bir JavaScript modülünü bir araya getirdim ( GitHub'a adadım :))

Kullanımı:

Hashcode.value("stackoverflow")
// -2559914341
Hashcode.value({ 'site' : "stackoverflow" })
// -3579752159

Javascript'in GC'si dairesel referanslara da boğulmuyor mu?
Clayton Rabenda

@Ryan Long Dairesel referanslarınız varsa, o zaman kodunuzu yeniden düzenlemeniz gerektiğini
söyleyebilirim

11
@Metalstorm "kodunuzu yeniden düzenlemeniz gerekiyor" Şaka mı yapıyorsunuz? Her DOM öğesi üst ve alt çifti döngüsel bir referans oluşturur.
Chris Middleton

8
Pek çok durumda aynı değeri döndüren, sayısal özelliklere sahip nesneleri hash etmek kötü bir iş yapar, yani var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.log(hash1, hash2);oturum açacaktır2867874173 2867874173
Julien Bérubé

9

JavaScript belirtimi, dizinlenmiş özellik erişimini, dizin adında bir toString dönüşümü gerçekleştirmek olarak tanımlar. Örneğin,

myObject[myProperty] = ...;

aynıdır

myObject[myProperty.toString()] = ...;

Bu JavaScript'teki gibi gereklidir

myObject["someProperty"]

aynıdır

myObject.someProperty

Ve evet, beni de üzüyor :-(



5

Referans: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

benzersiz anahtar ve erişim nesnesi oluşturmak için Es6 sembolünü kullanabilirsiniz. Symbol () öğesinden döndürülen her sembol değeri benzersizdir. Bir sembol değeri, nesne özellikleri için bir tanımlayıcı olarak kullanılabilir; veri türünün tek amacı budur.

var obj = {};

obj[Symbol('a')] = 'a';
obj[Symbol.for('b')] = 'b';
obj['c'] = 'c';
obj.d = 'd';

2
Sembolü yeniden oluşturmanın gerçekten bir yolu dışında x = Symbol ('a'); y = Sembolü ('a'); console.log (x === y); // yanlış döndürür Yani Sembol bir karma gibi çalışmaz.
Richard Collette

3

İşte benzersiz bir tamsayı döndüren basit çözümüm.

function hashcode(obj) {
    var hc = 0;
    var chars = JSON.stringify(obj).replace(/\{|\"|\}|\:|,/g, '');
    var len = chars.length;
    for (var i = 0; i < len; i++) {
        // Bump 7 to larger prime number to increase uniqueness
        hc += (chars.charCodeAt(i) * 7);
    }
    return hc;
}

2
Bunun karmaşıklığı, hashCode () arkasındaki tüm fikri zayıflatır
tuxSlayer

Bunu gereksiz yere karmaşık bulmuyorum. Merak ettim: neden değiştirme aşaması? Hariç tutmalar, aksi takdirde charCodeAt üzerinde iyi bir şekilde dönecekti, değil mi?
Greg Pettit

hashcode({a:1, b:2}) === hashcode({a:2, b:1})Ve diğer birçok çatışma nedeniyle çok kötü .
maaartinus

3

Başlığa dayanarak, js ile güçlü karmalar oluşturabiliriz, bir nesneden, bir dizi paramitten, bir dizeden veya başka bir şeyden benzersiz bir karma oluşturmak için kullanılabilir.

Daha sonra endekslemek için, parametrelerden bir dizin alınmasına izin verirken olası eşleştirme hatalarından kaçının (nesneyi aramak / döngü yapmaktan kaçının):

async function H(m) {
  const msgUint8 = new TextEncoder().encode(m)                       
  const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8)          
  const hashArray = Array.from(new Uint8Array(hashBuffer))                    
  const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
  console.log(hashHex)
}

/* Examples ----------------------- */
H("An obscure ....")
H(JSON.stringify( {"hello" : "world"} ))
H(JSON.stringify( [54,51,54,47] ))

Tarayıcımdaki yukarıdaki çıktı da sizin için eşit olmalı ( Gerçekten mi? ):

bf1cf3fe6975fe382ab392ec1dd42009380614be03d489f23601c11413cfca2b
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
d2f209e194045604a3b15bdfd7502898a0e848e4603c5a818bd01da69c00ad19

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string


1

Çözümüm, global Objectnesne için statik bir işlev sunuyor .

(function() {
    var lastStorageId = 0;

    this.Object.hash = function(object) {
        var hash = object.__id;

        if (!hash)
             hash = object.__id = lastStorageId++;

        return '#' + hash;
    };
}());

Bunun JavaScript'teki diğer nesne işleme işlevleri ile daha uygun olduğunu düşünüyorum.


1
Aynı dahili değerlere sahip nesneler farklı karma değerlere karma yapar, bu karma (kod) işlevi değildir.
Metalstorm

JavaScript'te (ve hemen hemen her dilde de düşünüyorum), aynı dahili değerlerle oluşturulan iki nesne hala farklı nesnelerdir, çünkü altta yatan veri türü her biri yeni bir nesne örneği ile temsil edilir. jsfiddle.net/h4G9f
Johnny

4
Evet ama bir hashcode bunun için değildir, hashcode'lar bir nesne durumunun eşitliğini kontrol etmek için kullanılır. Bir karma gibi, aynı girdiler girer (değişken değerler) aynı karma ortaya çıkar. Aradığınız şey bir UUID'dir (işlevinizin sağladığı şeydir).
Metalstorm

1
Haklısın. Soruyu yanlış anlıyorum. Gerçekten kötü, kabul edilen cevap da iyi bir çözüm sunmuyor.
Johnny

İşlevi de alarak, ben daha çok şöyle eğilimli olacaktır: jsfiddle.net/xVSsd Aynı sonuç, daha kısa (LoC + karakter) ve muhtemelen biraz daha küçük :)
Metalstorm

1

Diğer cevaplardan biraz daha derine gitmeye çalışacağım.

JS daha iyi hashing desteğine sahip olsa bile, sihirli bir şekilde her şeyi mükemmel bir şekilde hash etmez, birçok durumda kendi hash fonksiyonunuzu tanımlamanız gerekir. Örneğin Java'nın iyi karma desteği vardır, ancak yine de düşünmeniz ve biraz iş yapmanız gerekir.

Bir sorun karma / karma kodu ile ilgilidir ... kriptografik karma ve kriptografik olmayan karma vardır. Diğer sorun, karma işlemin neden faydalı olduğunu ve nasıl çalıştığını anlamak zorunda olmanızdır.

JavaScript veya Java'da karma hakkında konuştuğumuzda çoğu zaman kriptografik olmayan karma hakkında, genellikle hashmap / hashtable için karma hakkında konuşuyoruz (NodeJS kullanarak sunucu tarafında yapabileceğiniz kimlik doğrulama veya şifreler üzerinde çalışmadığımız sürece). ..).

Hangi verilere sahip olduğunuza ve ne elde etmek istediğinize bağlıdır.

Verilerinizde bazı doğal "basit" benzersizlikler var:

  • Tam sayının karması ... benzersiz olduğu için tam sayıdır, şanslısınız!
  • Bir dizenin karması ... dizeye bağlıdır, eğer dize benzersiz bir tanımlayıcıyı temsil ediyorsa, onu bir karma olarak düşünebilirsiniz (bu nedenle karma gerekmez).
  • Dolaylı olarak benzersiz bir tam sayı olan her şey en basit durumdur
  • Bu saygı gösterecektir: nesneler eşitse karma kod eşittir

Verilerinizde doğal bir "bileşik" benzersizlik var:

  • Örneğin, bir kişi nesnesiyle, ad, soyadı, doğum tarihi, ... kullanarak bir karma hesaplayabilirsiniz: Java'nın bunu nasıl yaptığını görün: Dizeler için İyi Karma İşlevi veya kullanıcı tabanınız için yeterince ucuz ve benzersiz olan diğer bazı kimlik bilgilerini kullanın

Verilerinizin ne olacağı hakkında hiçbir fikriniz yok:

  • İyi şanslar ... sen dize ve hash Java tarzı serileştirmek olabilir, ancak dize büyükse ve bu çarpışmalardan kaçınmayacak yanı sıra bir tamsayı (öz) hash demek olmaz pahalı olabilir.

Bilinmeyen veriler için sihirli olarak etkili bir karma tekniği yoktur, bazı durumlarda oldukça kolaydır, diğer durumlarda iki kez düşünmek zorunda kalabilirsiniz. Bu nedenle, JavaScript / ECMAScript daha fazla destek eklese bile, bu sorun için sihirli bir dil çözümü yoktur.

Uygulamada iki şeye ihtiyacınız var: yeterli benzersizlik, yeterli hız

Buna ek olarak: "nesneler eşitse hashcode eşittir"


0

Gerçekten davranış ayarlamak istiyorsanız (Java bilgisine gidiyorum), o zaman JavaScript'te bir çözüm bulmak zor olacak. Çoğu geliştirici, her nesneyi temsil etmek için benzersiz bir anahtar önerecektir, ancak bu, her biri benzersiz bir anahtarla iki özdeş nesne alabilmeniz için kümeden farklıdır. Java API, anahtarları değil karma kod değerlerini karşılaştırarak yinelenen değerleri kontrol etme işini yapar ve JavaScript'te nesnelerin karma kod değeri gösterimi olmadığından, aynısını yapmak neredeyse imkansız hale gelir. Prototype JS kütüphanesi bile şöyle der:

"Karma, benzersiz anahtarları değerlere bağlayan ilişkilendirilebilir bir dizi olarak düşünülebilir (ki bunlar mutlaka benzersiz değildir) ..."

http://www.prototypejs.org/api/hash


0

Göz kapaksızlığının cevabına ek olarak, herhangi bir nesne için tekrarlanabilir, benzersiz bir kimlik döndüren bir işlev:

var uniqueIdList = [];
function getConstantUniqueIdFor(element) {
    // HACK, using a list results in O(n), but how do we hash e.g. a DOM node?
    if (uniqueIdList.indexOf(element) < 0) {
        uniqueIdList.push(element);
    }
    return uniqueIdList.indexOf(element);
}

Gördüğünüz gibi, arama için çok verimsiz bir liste kullanıyor, ancak şimdilik bulabildiğim en iyisi.


0

Nesneleri anahtar olarak kullanmak istiyorsanız, burada daha önce bahsedildiği gibi toString Yönteminin üzerine yazmanız gerekir. Kullanılan hash işlevlerinin hepsi gayet iyi, ancak sadece eşit nesneler için değil aynı nesneler için çalışıyorlar.

Bu amaç için kolayca kullanabileceğiniz nesnelerden karma oluşturan küçük bir kütüphane yazdım. Nesnelerin farklı bir düzeni bile olabilir, karmalar aynı olacaktır. Dahili olarak karma için farklı türleri kullanabilirsiniz (djb2, md5, sha1, sha256, sha512, ripemd160).

Belgelerden küçük bir örnek:

var hash = require('es-hash');

// Save data in an object with an object as a key
Object.prototype.toString = function () {
    return '[object Object #'+hash(this)+']';
}

var foo = {};

foo[{bar: 'foo'}] = 'foo';

/*
 * Output:
 *  foo
 *  undefined
 */
console.log(foo[{bar: 'foo'}]);
console.log(foo[{}]);

Paket tarayıcıda ve Node-J'lerde kullanılabilir.

Depo: https://bitbucket.org/tehrengruber/es-js-hash


0

Bir arama nesnesinde benzersiz değerlere sahip olmak istiyorsanız, şöyle bir şey yapabilirsiniz:

Arama nesnesi oluşturma

var lookup = {};

Hashcode işlevini ayarlama

function getHashCode(obj) {
    var hashCode = '';
    if (typeof obj !== 'object')
        return hashCode + obj;
    for (var prop in obj) // No hasOwnProperty needed
        hashCode += prop + getHashCode(obj[prop]); // Add key + value to the result string
    return hashCode;
}

Nesne

var key = getHashCode({ 1: 3, 3: 7 });
// key = '1337'
lookup[key] = true;

Dizi

var key = getHashCode([1, 3, 3, 7]);
// key = '01132337'
lookup[key] = true;

Diğer çeşitler

var key = getHashCode('StackOverflow');
// key = 'StackOverflow'
lookup[key] = true;

Son sonuç

{ 1337: true, 01132337: true, StackOverflow: true }

getHashCodeNesne veya dizi boş olduğunda herhangi bir değer döndürmeyeceğini unutmayın

getHashCode([{},{},{}]);
// '012'
getHashCode([[],[],[]]);
// '012'

Bu yalnızca @ijmacd çözümü benzer getHashCodemevcut değil JSONbağımlılık.



@tuxSlayer Bana bildirdiğiniz için teşekkürler. Bu kodu ihtiyaçlarınızla kolayca genişletebilirsiniz, ancak umarım fikir biraz açıktır :)
A1rPun

Bu, bellek ve performansı oldukça
zorlayabilen

0

Göz kapaksızlığından ve KimKha'dan gelen cevapları birleştirdim.

Aşağıdaki bir açısaljs hizmetidir ve sayıları, dizeleri ve nesneleri destekler.

exports.Hash = () => {
  let hashFunc;
  function stringHash(string, noType) {
    let hashString = string;
    if (!noType) {
      hashString = `string${string}`;
    }
    var hash = 0;
    for (var i = 0; i < hashString.length; i++) {
        var character = hashString.charCodeAt(i);
        hash = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }

  function objectHash(obj, exclude) {
    if (exclude.indexOf(obj) > -1) {
      return undefined;
    }
    let hash = '';
    const keys = Object.keys(obj).sort();
    for (let index = 0; index < keys.length; index += 1) {
      const key = keys[index];
      const keyHash = hashFunc(key);
      const attrHash = hashFunc(obj[key], exclude);
      exclude.push(obj[key]);
      hash += stringHash(`object${keyHash}${attrHash}`, true);
    }
    return stringHash(hash, true);
  }

  function Hash(unkType, exclude) {
    let ex = exclude;
    if (ex === undefined) {
      ex = [];
    }
    if (!isNaN(unkType) && typeof unkType !== 'string') {
      return unkType;
    }
    switch (typeof unkType) {
      case 'object':
        return objectHash(unkType, ex);
      default:
        return stringHash(String(unkType));
    }
  }

  hashFunc = Hash;

  return Hash;
};

Örnek Kullanım:

Hash('hello world'), Hash('hello world') == Hash('hello world')
Hash({hello: 'hello world'}), Hash({hello: 'hello world'}) == Hash({hello: 'hello world'})
Hash({hello: 'hello world', goodbye: 'adios amigos'}), Hash({hello: 'hello world', goodbye: 'adios amigos'}) == Hash({goodbye: 'adios amigos', hello: 'hello world'})
Hash(['hello world']), Hash(['hello world']) == Hash(['hello world'])
Hash(1), Hash(1) == Hash(1)
Hash('1'), Hash('1') == Hash('1')

Çıktı

432700947 true
-411117486 true
1725787021 true
-1585332251 true
1 true
-1881759168 true

açıklama

Gördüğünüz gibi hizmetin kalbi KimKha tarafından yaratılan hash işlevidir. Nesnenin yapısı da son karma değerini etkileyecek şekilde dizelere türler ekledim.

göz kapaksızlığı nesne karşılaştırması, kendi kendini referanslayan nesneler tarafından sonsuz özyinelemeyi önlemek için kullanılır.

kullanım

Bu hizmeti, nesnelerle erişilen bir hata hizmetine sahip olabilmem için oluşturdum. Böylece bir hizmet belirli bir nesneyle hata kaydedebilir ve diğeri herhangi bir hatanın bulunup bulunmadığını belirleyebilir.

yani

JsonValidation.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'}, 'Invalid Json Syntax - key not double quoted');

UserOfData.js

ErrorSvc({id: 1, json: '{attr: "not-valid"}'});

Bu geri dönecektir:

['Invalid Json Syntax - key not double quoted']

Süre

ErrorSvc({id: 1, json: '{"attr": "not-valid"}'});

Bu geri dönecekti

[]

0

Sadece gizli gizli özelliği defineProperty enumerable: false

İşe çok hızlı :

  • İlk okunan benzersizId: 1.257.500 ops / s
  • Diğerleri: 309,226,485 ops / s
var nextObjectId = 1
function getNextObjectId() {
    return nextObjectId++
}

var UNIQUE_ID_PROPERTY_NAME = '458d576952bc489ab45e98ac7f296fd9'
function getObjectUniqueId(object) {
    if (object == null) {
        return null
    }

    var id = object[UNIQUE_ID_PROPERTY_NAME]

    if (id != null) {
        return id
    }

    if (Object.isFrozen(object)) {
        return null
    }

    var uniqueId = getNextObjectId()
    Object.defineProperty(object, UNIQUE_ID_PROPERTY_NAME, {
        enumerable: false,
        configurable: false,
        writable: false,
        value: uniqueId,
    })

    return uniqueId
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.