Existe algum tipo de função de código hash em JavaScript?

150

Basicamente, estou tentando criar um objeto de objetos únicos, um conjunto. Eu tive a brilhante idéia de apenas usar um objeto JavaScript com objetos para os nomes das propriedades. Tal como,

set[obj] = true;

Isso funciona, até certo ponto. Funciona muito bem com string e números, mas com outros objetos, todos parecem "hash" com o mesmo valor e acessam a mesma propriedade. Existe alguma maneira de gerar um valor de hash exclusivo para um objeto? Como seqüências de caracteres e números fazem isso, posso substituir o mesmo comportamento?

Boog
fonte
32
A razão pela qual todos os objetos 'hash' têm o mesmo valor é porque você não substituiu seus métodos toString. Como as chaves precisam ser cadeias de caracteres, o método toString é chamado automaticamente para obter uma chave válida, para que todos os seus objetos estejam convertendo na mesma cadeia padrão: "[objeto Objeto]".
18712 Alanning
4
JSON.stringify(obj)ou obj.toSource()pode funcionar para você, dependendo do problema e da plataforma de destino.
AnnanFay
4
@Annan JSON.stringify (obj) literalmente apenas converte o objeto (inteiro) em uma string. Então você basicamente copiava o objeto em si mesmo. Isso é inútil, um desperdício de espaço e não é o ideal.
MetalStorm
1
@Metalstorm True, é por isso que depende do seu problema. Quando encontrei essa pergunta no google, minha solução final foi chamar toSource () em objetos. Outro método seria apenas usar um hash convencional na fonte.
precisa saber é o seguinte
@Annan, toSourcenão funcionam no Chrome btw
Pacerier

Respostas:

35

Os objetos JavaScript podem usar apenas cadeias de caracteres como chaves (qualquer outra coisa é convertida em uma cadeia de caracteres).

Como alternativa, você pode manter uma matriz que indexa os objetos em questão e usar sua string de índice como uma referência ao objeto. Algo assim:

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

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

Obviamente, é um pouco detalhado, mas você pode escrever alguns métodos que lidam com isso e obter e definir tudo de maneira desagradável.

Editar:

Seu palpite é fato - esse é um comportamento definido no JavaScript - especificamente, ocorre uma conversão em toString, o que significa que você pode definir sua própria função toString no objeto que será usado como o nome da propriedade. - olliej

Isso traz outro ponto interessante; você pode definir um método toString nos objetos que deseja hash e que podem formar seu identificador de hash.

ausência de pálpebra
fonte
outra opção seria atribuir a cada objeto um valor aleatório como hash - talvez um número aleatório + total de ticks - e depois ter um conjunto de funções para adicionar / remover o objeto da matriz.
Sugendran 12/10/08
4
Isso falhará se você adicionar o mesmo objeto duas vezes. Vai pensar que é diferente.
2111 Daniel X Moore
"Isso falhará se você adicionar o mesmo objeto duas vezes. Ele pensará que é diferente." Bom ponto. Uma solução poderia ser a subclasse de Array para ObjectReference, conectando uma verificação duplicada em push (). Não tenho tempo para editar esta solução agora, mas espero lembrar mais tarde.
Eyelidlessness
8
Eu gosto dessa solução, porque ela não precisa de propriedades adicionais no objeto. Mas está ficando problemático, se você tentar ter um coletor de lixo limpo. Na sua abordagem, ele salvará o objeto, embora outras referências já tenham sido excluídas. Isso pode levar a problemas em aplicativos maiores.
19413 Johnny
35
Qual o sentido de fazer hash nos objetos se toda vez que você os consulta, precisa de uma verificação linear de uma matriz?
Bordaigorl
57

Se você deseja uma função hashCode () como Java em JavaScript, essa é sua:

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;
}

Essa é a maneira de implementação em Java (operador bit a bit).

Observe que o hashCode pode ser positivo e negativo, e isso é normal, consulte HashCode fornecendo valores negativos . Portanto, você pode considerar usar Math.abs()junto com esta função.

KimKha
fonte
5
isso cria -hash, não perfeito
qodeninja
2
@KimKha charé uma palavra reservada em JS e pode causar alguns problemas. Algum outro nome seria melhor.
218132 szeryf
16
@qodeninja diz quem? É a primeira vez que ouvi tal afirmação. Você pode criar um link para alguma fonte? Os hashes são geralmente calculados usando operações aritméticas e de bits inteiros de tamanho fixo, portanto, obter resultados positivos ou negativos é algo esperado.
szeryf
7
Exigente, mas ... "if (this.length == 0) return hash;" é redundante :) E mudaria pessoalmente "caractere" para "código".
Metalstorm
10
@qodeninja e @szeryf: você só precisa ter cuidado ao usá-lo. Por exemplo, tentei fazer pickOne["helloo".hashCode() % 20]uma matriz pickOnecom 20 elementos. Eu recebi undefinedporque o código de hash é negativo, então este é um exemplo em que alguém (eu) assumiu implicitamente códigos de hash positivos.
Jim Pivarski
31

A maneira mais fácil de fazer isso é atribuir a cada um de seus objetos seu próprio toStringmétodo exclusivo :

(function() {
    var id = 0;

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

Eu tive o mesmo problema e isso resolveu-o perfeitamente para mim com o mínimo de confusão e foi muito mais fácil reimplementar algum estilo Java gordo Hashtablee adicionar equals()e adicionar hashCode()às suas classes de objetos. Apenas certifique-se de não colocar uma string '<#MyObject: 12> no seu hash ou isso limpará a entrada do seu objeto existente com esse ID.

Agora todos os meus hashes estão totalmente relaxados. Também acabei de publicar uma entrada de blog há alguns dias sobre esse tópico exato .

Daniel X Moore
fonte
28
Mas isso erra o objetivo. Java possui equals()e, hashCode()portanto, dois objetos equivalentes têm o mesmo valor de hash. O uso do método acima significa que cada instância de MyObjectterá uma cadeia única, o que significa que você precisará manter uma referência a esse objeto para recuperar o valor correto do mapa. Ter uma chave não tem sentido, porque não tem nada a ver com a singularidade de um objeto. Uma toString()função útil precisará ser implementada para o tipo específico de objeto que você está usando como chave.
Sethro
@sethro, você pode implementar o toStringpara os objetos de forma que ele mapeie diretamente para uma relação de equivalência, para que dois objetos criem a mesma string se forem considerados "iguais".
Daniel X Moore
3
Certo, e essa é a única maneira correta de usar toString()para permitir que você use um Objectcomo a Set. Acho que não entendi sua resposta como uma tentativa de fornecer uma solução genérica para evitar escrever um toString()equivalente equals()ou hashCode()caso a caso.
Sethro
3
Votado. Este não é o que um hashcode é, ver as minhas respostas para: stackoverflow.com/a/14953738/524126 E uma verdadeira implementação de um hashcode: stackoverflow.com/a/15868654/524126
MetalStorm
5
@ Metalstorm, a pergunta não estava perguntando sobre um código de hash "verdadeiro", mas como usar com sucesso um objeto como um conjunto em JavaScript.
Daniel X Moore
20

O que você descreveu é coberto pelo Harmony WeakMaps , parte da especificação do ECMAScript 6 (próxima versão do JavaScript). Ou seja: um conjunto em que as chaves podem ser qualquer coisa (incluindo indefinidas) e não enumeráveis.

Isso significa que é impossível obter uma referência a um valor, a menos que você tenha uma referência direta à chave (qualquer objeto!) Vinculada a ele. É importante por várias razões de implementação de mecanismo relacionadas à eficiência e à coleta de lixo, mas também é super legal, pois permite novas semânticas, como permissões de acesso revogáveis ​​e passagem de dados sem expor o remetente.

Do MDN :

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

Os WeakMaps estão disponíveis no Firefox, Chrome e Edge atuais. Eles também são suportados no nó v7 e na v6 com o --harmony-weak-mapssinalizador.

slezica
fonte
1
Qual é a diferença entre estes e Map?
smac89
@ smac89 O WeakMap tem limitações: 1) Aceita apenas objetos como chaves 2) Nenhuma propriedade de tamanho 3) Nenhum iterador ou método forEach 4) Nenhum método claro. A chave é objeto - portanto, quando o objeto será excluído da memória - os dados do WeakMap conectado a esse objeto também serão excluídos. É muito útil quando queremos manter as informações, que devem existir apenas enquanto o objeto existe. Então WeakMap tem apenas métodos: set, suprima-o para gravação e obter, tem para leitura
Ekaterina Tokareva
Isso não funciona exatamente corretamente ... var m = new Map();m.set({},"abc"); console.log(m.get({}) //=>undefinedSó funciona se você tiver a mesma variável que você referenciou originalmente no comando set. EGvar m = new Map();a={};m.set(a,"abc"); console.log(m.get(a) //=>undefined
Sancarn
1
@ Santanc Não precisa ser a mesma variável, mas eles precisam apontar para o mesmo objeto. No seu primeiro exemplo, você tem dois objetos diferentes, eles têm a mesma aparência, mas têm um endereço diferente.
Svish
1
@Svish bom local! Embora eu sei que agora, eu não poderia ter feito naquela época :)
Sancarn
19

A solução que escolhi é semelhante à de Daniel, mas, em vez de usar uma fábrica de objetos e substituir o toString, adiciono explicitamente o hash ao objeto quando ele é solicitado pela primeira vez por meio da função getHashCode. Um pouco bagunçado, mas melhor para as minhas necessidades :)

Function.prototype.getHashCode = (function(id) {
    return function() {
        if (!this.hashCode) {
            this.hashCode = '<hash|#' + (id++) + '>';
        }
        return this.hashCode;
    }
}(0));
theGecko
fonte
7
Se você quiser seguir esse caminho, é muito melhor definir o hashCode via Object.definePropertycom enumerableset como false, para que você não troque nenhum for .. inloop.
Sebastian Nowak
14

Para minha situação específica, só me preocupo com a igualdade do objeto, tanto quanto as chaves e os valores primitivos. A solução que funcionou para mim foi converter o objeto em sua representação JSON e usá-lo como hash. Existem limitações como ordem de definição de chave potencialmente inconsistente; mas como eu disse, funcionou para mim porque todos esses objetos estavam sendo gerados em um só lugar.

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
// }
ijmacd
fonte
10

Eu montei um pequeno módulo JavaScript há algum tempo para produzir códigos de hash para strings, objetos, matrizes, etc. (acabei de o comprometer com o GitHub :))

Uso:

Hashcode.value("stackoverflow")
// -2559914341
Hashcode.value({ 'site' : "stackoverflow" })
// -3579752159
Tempestade de Metal
fonte
O GC do javascript também não se engasga com referências circulares?
Clayton Rabenda
@ Ryan Longa eu poderia ir tão longe como dizer se você tem referências circulares, então você precisa refatorar seu código;)
MetalStorm
11
@Metalstorm ", então você precisa refatorar o seu código" Você está brincando? Cada par pai e filho do elemento DOM constitui uma referência circular.
Chris Middleton
8
Ele faz um pobres objetos hash trabalho que têm propriedades numéricos, devolvendo o mesmo valor, em muitos casos, isto var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.log(hash1, hash2);irá registrar2867874173 2867874173
Julien Bérubé
9

A especificação JavaScript define o acesso à propriedade indexada como executando uma conversão toString no nome do índice. Por exemplo,

myObject[myProperty] = ...;

é o mesmo que

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

Isso é necessário, como no JavaScript

myObject["someProperty"]

é o mesmo que

myObject.someProperty

E sim, isso também me deixa triste :-(

olliej
fonte
5

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

você pode usar o símbolo Es6 para criar chave exclusiva e objeto de acesso. Todo valor de símbolo retornado de Symbol () é exclusivo. Um valor de símbolo pode ser usado como um identificador para propriedades do objeto; esse é o único objetivo do tipo de dados.

var obj = {};

obj[Symbol('a')] = 'a';
obj[Symbol.for('b')] = 'b';
obj['c'] = 'c';
obj.d = 'd';
Khalid Azam
fonte
2
Exceto que não há realmente uma maneira de regenerar o símbolo, deixe x = Symbol ('a'); deixe y = Symbol ('a'); console.log (x === y); // retorna false Portanto, o símbolo não funciona como um hash.
Richard Collette
3

Aqui está minha solução simples que retorna um número inteiro exclusivo.

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;
}
Timothy Perez
fonte
2
Complexidade desta mina a idéia por trás hashCode ()
tuxSlayer
Eu não acho isso desnecessariamente complexo. Fiquei curioso, porém: por que a fase de substituição? Caso contrário, as exclusões retornariam bem ao charCodeAt, não?
Greg Pettit
Muito ruim por causa hashcode({a:1, b:2}) === hashcode({a:2, b:1})e muitos outros conflitos.
maaartinus 30/03
3

Com base no título, podemos gerar hashes fortes com js, ele pode ser usado para gerar um hash exclusivo de um objeto, uma matriz de parâmetros, uma string ou qualquer outra coisa.

Posteriormente, para indexar isso, evite possíveis erros de correspondência, enquanto permite recuperar um índice dos parâmetros (evite pesquisar / fazer um loop no objeto, etc.):

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] ))

A saída acima no meu navegador também deve ser igual para você ( é mesmo? ):

bf1cf3fe6975fe382ab392ec1dd42009380614be03d489f23601c11413cfca2b
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
d2f209e194045604a3b15bdfd7502898a0e848e4603c5a818bd01da69c00ad19

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

NVRM
fonte
1

Minha solução introduz uma função estática para o Objectobjeto global .

(function() {
    var lastStorageId = 0;

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

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

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

Eu acho que isso é mais conveniente com outras funções de manipulação de objetos em JavaScript.

Johnny
fonte
1
Objetos com os mesmos valores internos serão hash para hashes diferentes, não é isso que um hash (código) faz.
Metalstorm
No JavaScript (e acho que em quase todas as outras línguas também), dois objetos criados com os mesmos valores internos ainda são objetos diferentes, porque o tipo de dados subjacente é representado por uma nova instância de objeto cada. jsfiddle.net/h4G9f
Johnny
4
Sim, mas não é para isso que serve um código de hash, códigos de hash são usados ​​para verificar a igualdade de um estado de objetos. Assim como um hash, as mesmas entradas entram (valores variáveis) o mesmo hash sai. O que você está procurando é um UUID (que é o que sua função fornece).
Metalstorm
1
Você está certo. Não entendi bem a pergunta. Muito ruim, que a resposta aceita também não fornece uma boa solução.
26614 Johnny
Tomar o seu função, bem, eu estaria inclinado a por isso mais como esta: jsfiddle.net/xVSsd Mesmo resultado, mais curtos (caracteres Linha de Controlo +) e, provavelmente, uma pequena pouquinho mais rápido :)
MetalStorm
1

Vou tentar ir um pouco mais fundo do que outras respostas.

Mesmo se o JS tivesse um suporte melhor ao hash, ele não usaria magicamente tudo perfeitamente, em muitos casos, você terá que definir sua própria função de hash. Por exemplo, Java possui um bom suporte de hash, mas você ainda precisa pensar e fazer algum trabalho.

Um problema é com o termo hash / hashcode ... há hash criptográfico e hash não criptográfico. O outro problema é que você precisa entender por que o hash é útil e como ele funciona.

Quando falamos sobre hash em JavaScript ou Java, na maioria das vezes, falamos sobre hash não criptográfico, geralmente sobre hash para hashmap / hashtable (a menos que trabalhemos em autenticação ou senhas, o que você poderia fazer no servidor usando o NodeJS. ..)

Depende dos dados que você possui e do que deseja alcançar.

Seus dados têm alguma singularidade "simples" natural:

  • O hash de um número inteiro é ... o número inteiro, pois é único, sorte sua!
  • O hash de uma string ... depende da string, se a string representar um identificador exclusivo, você pode considerá-lo como um hash (portanto, não é necessário fazer hash).
  • Qualquer coisa que seja indiretamente um número inteiro único é o caso mais simples
  • Isso respeitará: hashcode igual se os objetos forem iguais

Seus dados têm alguma exclusividade "composta" natural:

  • Por exemplo, com um objeto de pessoa, você pode calcular um hash usando nome, sobrenome, data de nascimento, ... veja como o Java faz isso: Função Hash Bom para Strings , ou use outras informações de ID que sejam baratas e exclusivas o suficiente para sua base de dados

Você não tem idéia de quais serão seus dados:

  • Boa sorte ... você pode serializar para string e hash no estilo Java, mas isso pode ser caro se a string for grande e não evitar colisões, como também dizer o hash de um número inteiro (self).

Não existe uma técnica de hash magicamente eficiente para dados desconhecidos; em alguns casos, é bastante fácil; em outros casos, pode ser necessário pensar duas vezes. Portanto, mesmo que o JavaScript / ECMAScript inclua mais suporte, não há solução de linguagem mágica para esse problema.

Na prática, você precisa de duas coisas: singularidade suficiente, velocidade suficiente

Além disso, é ótimo ter: "código de hash igual se os objetos forem iguais"

Christophe Roussy
fonte
0

Se você realmente deseja definir um comportamento (estou familiarizado com o conhecimento de Java), será difícil encontrar uma solução em JavaScript. A maioria dos desenvolvedores recomendará uma chave exclusiva para representar cada objeto, mas isso é diferente do definido, pois você pode obter dois objetos idênticos, cada um com uma chave exclusiva. A API Java realiza o trabalho de verificação de valores duplicados comparando valores de código de hash, não chaves, e como não há representação de valor de código de hash de objetos em JavaScript, torna-se quase impossível fazer o mesmo. Até a biblioteca Prototype JS admite essa falha, quando diz:

"Hash pode ser pensado como uma matriz associativa, vinculando chaves únicas a valores (que não são necessariamente únicos) ..."

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


fonte
0

Além da resposta da ausência de pálpebra, aqui está uma função que retorna um ID exclusivo e reproduzível para qualquer objeto:

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);
}

Como você pode ver, ele usa uma lista de pesquisa que é muito ineficiente, mas é o melhor que pude encontrar por enquanto.

cburgmer
fonte
0

Se você quiser usar objetos como chaves, precisará substituir o método toString, como alguns já mencionados aqui. As funções de hash usadas são boas, mas funcionam apenas para os mesmos objetos e não para objetos iguais.

Eu escrevi uma pequena biblioteca que cria hashes a partir de objetos, que você pode usar facilmente para esse fim. Os objetos podem até ter uma ordem diferente, os hashes serão os mesmos. Internamente, você pode usar tipos diferentes para seu hash (djb2, md5, sha1, sha256, sha512, ripemd160).

Aqui está um pequeno exemplo da documentação:

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[{}]);

O pacote pode ser usado no navegador e nos Nó-Js.

Repositório: https://bitbucket.org/tehrengruber/es-js-hash

darthmatch
fonte
0

Se você deseja ter valores exclusivos em um objeto de pesquisa, pode fazer algo assim:

Criando um objeto de pesquisa

var lookup = {};

Configurando a função hashcode

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;
}

Objeto

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

Matriz

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

Outros tipos

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

Resultado final

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

Observe que getHashCodenão retorna nenhum valor quando o objeto ou a matriz está vazia

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

Isso é semelhante à solução @ijmacd, apenas getHashCodenão tem JSONdependência.

A1rPun
fonte
Você tem que ter um problema com referências circulares com que
tuxSlayer
@tuxSlayer Obrigado por me informar. Você poderia facilmente expandir este código com as suas necessidades, mas espero que a idéia é pouco claro :)
A1rPun
Isto irá produzir chaves muito longas para objetos grandes, que poderia atingir a memória e desempenho muito difícil
Gérson
0

Combinei as respostas de eyelidlessness e KimKha.

A seguir, é um serviço angularjs e suporta números, seqüências de caracteres e objetos.

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;
};

Exemplo de uso:

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')

Resultado

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

Explicação

Como você pode ver, o coração do serviço é a função hash criada por KimKha. Adicionei tipos às seqüências de caracteres para que a estrutura do objeto também impactasse o valor final do hash. As chaves são hash para evitar colisões de objetos |

A comparação de objetos sem pálpebras é usada para evitar recursões infinitas por objetos auto-referenciados.

Uso

Eu criei este serviço para poder ter um serviço de erro que é acessado com objetos. Para que um serviço possa registrar um erro em um determinado objeto e outro possa determinar se foram encontrados erros.

ie

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"}'});

Isso retornaria:

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

Enquanto

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

Isso retornaria

[]
jozsef morrissey
fonte
0

Basta usar a propriedade secreta oculta com o defineProperty enumerable: false

Funciona muito rápido :

  • A primeira leitura únicaId: 1.257.500 ops / s
  • Todos os outros: 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
}
Nikolay Makhonin
fonte