Чи є якась функція коду хеш-коду в JavaScript?


150

В основному я намагаюся створити об’єкт унікальних об’єктів, набір. У мене була геніальна ідея просто використовувати об’єкт JavaScript з об’єктами для імен властивостей. Як от,

set[obj] = true;

Це працює, до певного моменту. Він чудово працює з рядками та числами, але з іншими об'єктами вони, здається, "хешують" однакове значення та отримують доступ до тієї ж властивості. Чи існує якийсь спосіб я генерую унікальне хеш-значення для об'єкта? Як це роблять рядки та цифри, чи можу я змінити ту саму поведінку?


32
Причина, що всі об’єкти «хешують» на одне значення, полягає в тому, що ви не перекрили їхні методи toString. Оскільки ключі повинні бути рядками, метод toString автоматично викликається для отримання дійсного ключа, тому всі ваші об'єкти перетворюються на одну і ту ж рядок за замовчуванням: "[object Object]".
алан

4
JSON.stringify(obj)або obj.toSource()може працювати для вас залежно від проблеми та цільової платформи.
AnnanFay

4
@Annan JSON.stringify (obj) буквально просто перетворює (цілий) об'єкт у рядок. Таким чином, ви в основному просто копіюєте об'єкт на себе. Це безглуздо, марна трата місця і не оптимальна.
Metalstorm

1
@Metalstorm Правда, саме тому залежить, у чому полягає ваша проблема. Коли я знайшов це питання через google, моє остаточне рішення викликав toSource () на об’єкти. Іншим методом було б просто використання звичайного хешу на джерело.
AnnanFay

@Annan, toSourceне працюй у Chrome btw
Pacerier

Відповіді:


35

Об'єкти JavaScript можуть використовувати лише рядки як ключі (все інше перетворюється у рядок).

Можна також підтримувати масив, який індексує об'єкти, про які йдеться, і використовувати його рядок індексів як посилання на об'єкт. Щось на зразок цього:

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

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

Очевидно, що це трохи дослівно, але ви можете написати пару методів, які впораються з цим, і отримують і встановлюють все невольно.

Редагувати:

Ваша здогадка - це факт - це визначена поведінка в JavaScript - конкретно, відбувається перетворення toString, що означає, що ви можете визначити власну функцію toString на об'єкті, який буде використовуватися як ім'я властивості. - olliej

Це викликає ще один цікавий момент; ви можете визначити метод toString для об’єктів, які ви хочете хеш, і які можуть формувати їх ідентифікатор хеша.


іншим варіантом буде дати кожному об'єкту випадкове значення, оскільки це хеш - можливо випадкове число + загальна кількість галочок - тоді мати набір функцій для додавання / видалення об'єкта з масиву.
Сугендран

4
Це не вдасться, якщо два рази додати той самий об’єкт. Він подумає, що це інакше.
Даніель X Мур

"Це не вдасться, якщо два рази додати один і той же об'єкт. Він подумає, що він інший." Гарна думка. Рішенням може бути підклас Array для ObjectReference, підключення дублікату check у push (). Зараз я не встигаю редагувати це рішення, але сподіваюся, що згадаю пізніше.
безглаздість

8
Мені подобається це рішення, оскільки воно не потребує додаткових властивостей в об’єкті. Але це стає проблематичним, якщо спробувати мати чистий сміттєзбірник. У вашому підході він збереже об'єкт, хоча його інші посилання вже були видалені. Це може призвести до проблем у великих програмах.
Джонні

35
Який сенс хешувати об’єкти, якщо кожного разу, коли ви звертаєтесь до них, потрібно лінійне сканування масиву?
Bordaigorl

57

Якщо ви хочете функцію hashCode (), як Java у JavaScript, це ваше:

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 (розрядний оператор).

Зауважте, що hashCode може бути позитивним та негативним, і це нормально, див. HashCode, що дає негативні значення . Отже, ви можете розглянути можливість використання Math.abs()поряд з цією функцією.


5
це створює -хаш, не ідеально
qodeninja

2
@KimKha charє зарезервованим словом у JS і може спричинити деякі проблеми. Ще якесь ім’я було б краще.
szeryf

16
@qodeninja каже хто? Вперше я почув таке твердження. Чи можете ви пов’язати якесь джерело? Хеші зазвичай обчислюються за допомогою арифметичних та бітових операцій фіксованого розміру, тому отримання позитивних чи негативних результатів варто очікувати.
szeryf

7
Вибагливий, але ... "якщо (this.length == 0) повернути хеш;" зайве :) І особисто змінив би "символ" на "код".
Metalstorm

10
@qodeninja та @szeryf: ви просто повинні бути обережними, як ви їх використовуєте. Наприклад, я намагався зробити pickOne["helloo".hashCode() % 20]масив pickOneз 20 елементами. Я отримав, undefinedоскільки хеш-код негативний, тому це приклад, коли хтось (я) неявно приймав позитивні хеш-коди.
Джим Піварський

31

Найпростіший спосіб зробити це - надати кожному своєму об’єкту свій унікальний toStringметод:

(function() {
    var id = 0;

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

У мене була така ж проблема, і це вирішило її ідеально для мене з мінімальною суєтою, і було набагато простіше, щоб повторно реалізувати якийсь жирний стиль Java Hashtableта додавати equals()і hashCode()до ваших об’єктних класів. Просто переконайтесь, що ви також не вставляєте рядок '<#MyObject: 12> у свій хеш, інакше це видалить запис вашого вибуваючого об'єкта з цим ідентифікатором.

Тепер усі мої хеши абсолютно прохолодні. Я також щойно опублікував запис у блозі кілька днів тому про цю точну тему .


28
Але це пропускає всю суть. Java має equals()і hashCode()так , що дві еквівалентні об'єкти мають однакове значення хеш - функції. Використання вищевказаного методу означає, що кожен екземпляр MyObjectбуде мати унікальну рядок, а це означає, що вам доведеться зберігати посилання на цей об’єкт, щоб коли-небудь отримати правильне значення з карти. Мати ключ - безглуздо, тому що воно не має нічого спільного з унікальністю об’єкта. Корисна toString()функція повинна бути реалізована для конкретного типу об'єкта, який ви використовуєте як ключ.
sethro

@sethro ви можете реалізувати toStringдля об'єктів таким чином, що він безпосередньо відображає відношення еквівалентності, щоб два об'єкти створили однаковий рядок iff, якщо вони вважаються "рівними".
Даніель Х Мур

3
Правильно, і це єдиний правильний спосіб, toString()який дозволяє вам використовувати Objectяк Set. Я думаю, що я неправильно зрозумів вашу відповідь як намагання надати загальне рішення, щоб уникнути написання toString()еквіваленту equals()або hashCode()в кожному випадку.
sethro

3
Похитується. Це не те, що є хеш-код, дивіться мої відповіді на: stackoverflow.com/a/14953738/524126 І справжня реалізація хеш-коду: stackoverflow.com/a/15868654/524126
Metalstorm

5
@Metalstorm питання не задавало питання про "справжній" хеш-код, а про те, як успішно використовувати об'єкт як набір у JavaScript.
Даніель Х Мур

20

Те, що ви описали, охоплюється Harmony WeakMaps , частиною специфікації ECMAScript 6 (наступна версія JavaScript). Тобто: набір, де ключі можуть бути будь-якими (включаючи невизначені) і не перелічується.

Це означає, що неможливо отримати посилання на значення, якщо у вас немає прямого посилання на ключ (будь-який об’єкт!), Який посилається на нього. Це важливо для ряду причин впровадження двигуна, що стосуються ефективності та збору сміття, але це також дуже здорово, оскільки він дозволяє отримувати нові семантики, як відкликані дозволи доступу та передача даних, не піддаючи відправника даних.

Від 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

Слабкі карти доступні в поточних Firefox, Chrome та Edge. Вони також підтримуються в Node v7 та v6 з --harmony-weak-mapsпрапором.


1
Яка різниця між цими та Map?
smac89

@ smac89 WeakMap має обмеження: 1) Бере лише об'єкти як ключі 2) Немає властивості розміру 3) Ні ітератора, ні методу forEach 4) Немає чіткого методу. Ключовим є об’єкт - тому, коли об’єкт буде видалено з пам'яті - дані з WeakMap, пов'язані з цим об'єктом, також будуть видалені. Це дуже корисно, коли ми хочемо зберігати інформацію, яка повинна існувати лише доки існує об'єкт. Тож у WeakMap є лише методи: встановити, видалити для запису та отримати, має для читання
Катерина Токарева

Це не працює коректно ... var m = new Map();m.set({},"abc"); console.log(m.get({}) //=>undefinedЦе працює лише за наявності тієї самої змінної, на яку ви спочатку посилалися в команді set. EGvar m = new Map();a={};m.set(a,"abc"); console.log(m.get(a) //=>undefined
Санкарн

1
@Sancarn Це не повинно бути однаковою змінною, але вони повинні вказувати на один і той же об'єкт. У вашому першому прикладі у вас два різних об'єкти, вони виглядають однаково, але мають різну адресу.
Svish

1
@Svish гарне місце! Хоча я це зараз знаю, я, можливо, цього не зробив би :)
Санкарн

19

Я вибрав рішення, схоже на рішення Даніеля, але замість того, щоб використовувати фабрику об'єктів і переосмислювати ToString, я явно додаю хеш до об'єкта, коли він вперше запитується через функцію getHashCode. Трохи безладно, але краще для моїх потреб :)

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

7
Якщо ви хочете піти цим шляхом, набагато краще встановити hashCode via Object.definePropertywith enumerableset на false, щоб ви не зламали жодних for .. inциклів.
Себастьян Новак

14

Для моєї конкретної ситуації я дбаю лише про рівність об'єкта, наскільки це стосується ключів та примітивних значень. Для мене працювало рішення перетворити об'єкт на його JSON-представлення та використовувати його як хеш. Існують такі обмеження, як порядок визначення ключових слів, який може бути непослідовним; але, як я сказав, це працювало на мене, тому що всі ці об'єкти створюються в одному місці.

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

Нещодавно я зібрав невеликий модуль JavaScript, щоб створити хеш-коди для рядків, об'єктів, масивів тощо (я просто скористався цим GitHub :))

Використання:

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

Чи не утримується GC javascript і на кругових посиланнях?
Клейтон Рабенда

@Ryan Long Я можу сказати, якщо у вас є кругові посилання, тоді вам потрібно переробити код;)
Metalstorm

11
@Metalstorm ", то вам потрібно переробити код" Ви жартуєте? Кожен батьківський та дочірній елемент елемента DOM є циркулярним еталоном.
Кріс Міддлтон

8
Це погана робота з хешуючими об'єктами, що мають числові властивості, повертаючи одне і те ж значення у багатьох випадках, тобто здійснюватиме var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.log(hash1, hash2);реєстрацію2867874173 2867874173
Жульєн Берубе

9

Специфікація JavaScript визначає індексований доступ до властивостей як виконання перетворення toString на ім'я індексу. Наприклад,

myObject[myProperty] = ...;

те саме, що

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

Це необхідно, як і в JavaScript

myObject["someProperty"]

те саме, що

myObject.someProperty

І так, мене також сумує :-(


9

У ECMAScript 6 тепер є Setте, що працює як ви хочете: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

Він уже доступний в останніх Chrome, FF та IE11.


1
Це має бути головна відповідь у 2016 році. Якщо ви користуєтесь Babel, ви можете використовувати Set за специфікацією ES6, і вона буде автоматично заповнена на виході ES5. babeljs.io/docs/learn-es2015/#map-set-weak-map-weak-set
atroberts20

5

Довідка: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

ви можете використовувати символ Es6 для створення унікального ключа та об’єкта доступу. Кожне значення символу, повернене з Symbol (), є унікальним. Значення символу може використовуватися як ідентифікатор властивостей об'єкта; це єдине призначення типу даних.

var obj = {};

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

2
За винятком того, що насправді не існує способу відновлення символу, нехай x = Symbol ('a'); нехай y = Symbol ('a'); console.log (x === y); // повертає помилково, тому Symbol не працює як хеш.
Річард Коллетт

3

Ось моє просте рішення, яке повертає унікальне ціле число.

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
Складність цього підриває всю ідею за хеш-
кодом

Я не вважаю це надмірно складним. Мені було цікаво, однак: чому фаза заміни? Виключення б інакше повернули б штраф на charCodeAt, чи не так?
Грег Петтіт

Дуже погано через hashcode({a:1, b:2}) === hashcode({a:2, b:1})та багато інших конфліктів.
maaartinus

3

Виходячи з заголовка, ми можемо генерувати сильні хеші з js, його можна використовувати для створення унікального хешу з об’єкта, масиву парам, рядка чи будь-чого іншого.

Пізніше для індексації цього уникайте будь-яких можливих помилок відповідності, дозволяючи отримати індекс із парам (уникайте пошуку / циклічного об єкту тощо):

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

Вищенаведений вихід у моєму браузері, він повинен бути рівним і для вас ( це справді? ):

bf1cf3fe6975fe382ab392ec1dd42009380614be03d489f23601c11413cfca2b
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
d2f209e194045604a3b15bdfd7502898a0e848e4603c5a818bd01da69c00ad19

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


1

Моє рішення вводить статичну функцію для глобального Objectоб'єкта.

(function() {
    var lastStorageId = 0;

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

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

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

Я думаю, що це зручніше з іншими функціями маніпулювання об'єктами в JavaScript.


1
Об'єкти з однаковими внутрішніми значеннями будуть хешувати різні хеші, це не те, що робить хеш (код).
Metalstorm

У JavaScript (і я думаю, що майже в будь-якій іншій мові) два об'єкти, створені з однаковими внутрішніми значеннями, все ще є різними об'єктами, оскільки тип даних, що лежать нижче, представлений кожним новим екземпляром об'єкта. jsfiddle.net/h4G9f
Джонні

4
Так, але для цього не хеш-код, хеш-коди використовуються для перевірки рівності стану об'єктів. Так само, як і хеш, входять ті самі входи (змінні значення) виходить той же хеш. Те, що ви шукаєте, - це UUID (саме це забезпечує ваша функція).
Metalstorm

1
Ти маєш рацію. Я неправильно розумію питання. Дійсно погано, що прийнята відповідь також не дає хорошого рішення.
Джонні

Виконуючи вашу функцію, я схиляюся до того, щоб це було більше подібне до цього: jsfiddle.net/xVSsd Такий же результат, коротший (LoC + символи) і, мабуть, крихітний крихітка швидше :)
Metalstorm

1

Я спробую зайти трохи глибше, ніж інші відповіді.

Навіть якби JS отримала кращу підтримку хешування, вона не магічно б'є все ідеально, у багатьох випадках вам доведеться визначити власну хеш-функцію. Наприклад, у Java є хороша підтримка хешування, але ви все ще повинні подумати і виконати певну роботу.

Одна проблема полягає в терміні хеш / хеш-код ... є криптографічний хешинг та некриптографічний хешинг. Інша проблема - ви повинні зрозуміти, чому хеширование корисне і як воно працює.

Коли ми говоримо про хешування в JavaScript або Java, ми велику частину часу говоримо про некриптографічне хешуваннявання, як правило, про хешування для хешмапу / хештелю (якщо тільки ми не працюємо над автентифікацією або паролями, які ви могли б робити на сервері за допомогою NodeJS. ..).

Це залежить від того, які дані у вас є і що ви хочете досягти.

Ваші дані мають природну "просту" унікальність:

  • Хеш цілого числа - це ціле число, наскільки воно унікальне, щастить вам!
  • Хеш рядка ... це залежить від рядка, якщо рядок являє собою унікальний ідентифікатор, ви можете розглянути його як хеш (тому хешування не потрібно).
  • Все, що є опосередковано майже унікальним цілим числом, є найпростішим випадком
  • Це стосується: хеш-код рівний, якщо об'єкти рівні

Ваші дані мають певну природну "композитну" унікальність:

  • Наприклад, з об'єктом "людина" ви можете обчислити хеш, використовуючи ім'я, прізвище, дату народження, ... подивіться, як це робить Java: Функція хорошого хешу для рядків , або використовувати іншу інформацію про ідентифікацію, яка є дешевою і унікальною для вашої корисної справи

Ви поняття не маєте, якими будуть ваші дані:

  • Удачі ... Ви можете серіалізувати на string та хеш-стилі Java, але це може бути дорого, якщо рядок є великим, і він не уникне зіткнень, а також скажіть хеш цілого числа (self).

Не існує магічно ефективної методики хешування для невідомих даних, в деяких випадках це досить просто, в інших випадках вам може доведеться подумати двічі. Тож навіть якщо JavaScript / ECMAScript додає більше підтримки, для цієї проблеми не існує магічного рішення мови.

На практиці потрібно дві речі: достатня унікальність, достатня швидкість

На додаток до цього чудово мати: "хеш-код рівний, якщо об'єкти рівні"


0

Якщо ви справді хочете встановити поведінку (я збираюся на знаннях Java), тоді вам буде важко знайти рішення в JavaScript. Більшість розробників порекомендує унікальний ключ для представлення кожного об'єкта, але це на відміну від набору, оскільки ви можете отримати два однакові об’єкти, кожен з яких має унікальний ключ. Java API виконує роботу з перевірки дублікатів значень, порівнюючи значення хеш-коду, а не ключів, і оскільки в JavaScript не існує представлення значень хеш-коду, це зробити майже неможливо. Навіть бібліотека прототипу JS визнає цей недолік, коли говорить:

"Хеш може розглядатися як асоціативний масив, прив'язуючи унікальні ключі до значень (які не обов'язково є унікальними) ..."

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


0

Окрім відповіді на безвічність, тут є функція, яка повертає відтворюваний унікальний ідентифікатор для будь-якого об’єкта:

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

Як ви бачите, він використовує список для пошуку, який є дуже неефективним, однак це найкраще, що я міг знайти зараз.


0

Якщо ви хочете використовувати об'єкти як ключі, вам потрібно перезаписати їх у метод StSring, як деякі згадані тут. Хеш-функції, які були використані, все добре, але вони працюють лише для одних і тих же об'єктів, а не для рівних об'єктів.

Я написав невелику бібліотеку, яка створює хеші з об’єктів, які ви можете легко використовувати для цієї мети. Об'єкти можуть навіть мати інший порядок, хеші будуть однаковими. Внутрішньо ви можете використовувати різні типи для свого хешу (djb2, md5, sha1, sha256, sha512, ripemd160).

Ось невеликий приклад з документації:

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

Пакет можна використовувати як у браузері, так і в Node-Js.

Репозиторій: https://bitbucket.org/tehrengruber/es-js-hash


0

Якщо ви хочете мати унікальні значення в об’єкті пошуку, ви можете зробити щось подібне:

Створення об’єкта пошуку

var lookup = {};

Налаштування функції хеш-коду

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

Об'єкт

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

Масив

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

Інші типи

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

Кінцевий результат

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

Зверніть увагу, що getHashCodeне повертає жодного значення, коли об'єкт або масив порожні

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

Це схоже на рішення @ijmacd, тільки getHashCodeне має JSONзалежності.


У вас має бути проблема з циркулярними посиланнями на це
tuxSlayer

@tuxSlayer Дякую за те, що повідомили мені. Ви можете легко розширити цей код відповідно до своїх потреб, але сподіваюся, ідея дещо зрозуміла :)
A1rPun

Це дозволить створити дуже довгі клавіші для великих об'єктів, які можуть вразити пам'ять та продуктивність досить важко
Гершом

0

Я поєднав відповіді від бездушності та Кімха.

Далі йде послуга angularjs, яка підтримує числа, рядки та об'єкти.

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

Приклад використання:

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

Вихідні дані

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

Пояснення

Як ви бачите, серцем служби є хеш-функція, створена KimKha.Я додав типи до рядків, щоб структура об’єкта також вплинула на остаточне значення хешу. Клавіші хешируються, щоб запобігти зіткненням масиву |

Порівняння об'єктів без повік використовується для запобігання нескінченної рекурсії шляхом самовідвідування об'єктів.

Використання

Я створив цю службу, щоб у мене була служба помилок, до якої звертаються об’єкти. Так що одна служба може зареєструвати помилку із заданим об’єктом, а інша може визначити, чи були знайдені помилки.

тобто

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

Це поверне:

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

Поки

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

Це повернеться

[]

0

Просто використовуйте приховані секретні властивості разом із defineProperty enumerable: false

Це працює дуже швидко :

  • Перше прочитане унікальнеId: 1 257 500 ops / s
  • Всі інші: 309,226,485 оп / с
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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.