Есть ли в JavaScript какая-либо функция хэш-кода?

В основном я пытаюсь создать объект из уникальных предметов, набор. У меня возникла блестящая идея просто использовать объект JavaScript с объектами для имен свойств. Такие как,

set[obj] = true;

Это работает до определенной степени. Он отлично работает со строками и числами, но с другими объектами кажется, что все они «хешируют» одно и то же значение и обращаются к одному и тому же свойству. Есть ли способ сгенерировать уникальное хеш-значение для объекта? Как это делают строки и числа, могу ли я отменить то же поведение?

Причина, по которой все объекты имеют одно и то же значение, заключается в том, что вы не переопределили их методы toString. Поскольку ключи должны быть строками, метод toString автоматически вызывается для получения действительного ключа, поэтому все ваши объекты преобразуются в одну и ту же строку по умолчанию: «[object Object]».

alanning 16.02.2012 21:45

JSON.stringify(obj) или obj.toSource() могут работать для вас в зависимости от проблемы и целевой платформы.

AnnanFay 10.07.2013 03:07

@Annan JSON.stringify (obj) буквально просто преобразует (весь) объект в строку. Таким образом, вы просто копируете объект на себя. Это бессмысленно, бесполезно и неоптимально.

Metalstorm 26.04.2014 20:40

@Metalstorm True, поэтому все зависит от вашей проблемы. Когда я нашел этот вопрос через Google, мое окончательное решение вызвало toSource () для объектов. Другой способ - использовать обычный хеш для источника.

AnnanFay 27.04.2014 21:53

@Annan, toSource не работает в Chrome, кстати

Pacerier 19.09.2017 01:41
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
151
5
208 954
20
Перейти к ответу Данный вопрос помечен как решенный

Ответы 20

Ответ принят как подходящий

Объекты JavaScript могут использовать только строки в качестве ключей (все остальное преобразуется в строку).

В качестве альтернативы вы можете поддерживать массив, который индексирует рассматриваемые объекты, и использовать его строку индекса в качестве ссылки на объект. Что-то вроде этого:

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

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

Очевидно, это немного многословно, но вы могли бы написать пару методов, которые справятся с этим, и получить и установить все волей-неволей.

Редактировать:

Your guess is fact -- this is defined behaviour in JavaScript -- specifically a toString conversion occurs meaning that you can can define your own toString function on the object that will be used as the property name. - olliej

Это поднимает еще один интересный момент; вы можете определить метод toString для объектов, которые вы хотите хэшировать, и который может формировать их хэш-идентификатор.

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

Sugendran 12.10.2008 04:52

Это не удастся, если вы добавите один и тот же объект дважды. Он будет думать, что это другое.

Daniel X Moore 25.05.2009 02:46

«Это не удастся, если вы добавите один и тот же объект дважды. Он будет думать, что это другой». Хорошая точка зрения. Решением может быть подкласс Array для ObjectReference, подключив дублирующую проверку к push (). У меня сейчас нет времени редактировать это решение, но я надеюсь, что вспомню об этом позже.

eyelidlessness 26.05.2009 17:24

Мне нравится это решение, потому что оно не требует каких-либо дополнительных свойств в объекте. Но это становится проблематичным, если вы пытаетесь получить чистый сборщик мусора. В вашем подходе он сохранит объект, хотя другие ссылки уже были удалены. Это может привести к проблемам в более крупных приложениях.

Johnny 19.02.2013 13:06

Какой смысл хешировать объекты, если каждый раз, когда вы обращаетесь к ним, вам нужно линейное сканирование массива?

Bordaigorl 16.11.2014 14:36

Я думал, что объекты JavaScript также могут использовать символы в качестве ключей ...?

mesqueeb 20.01.2020 10:09

Если вы действительно хотите установить поведение (я исхожу из знания Java), вам будет сложно найти решение в JavaScript. Большинство разработчиков рекомендуют уникальный ключ для представления каждого объекта, но в отличие от набора, вы можете получить два идентичных объекта, каждый с уникальным ключом. API Java выполняет работу по проверке повторяющихся значений путем сравнения значений хэш-кода, а не ключей, и, поскольку в JavaScript нет представления значений хэш-кода объектов, сделать то же самое становится практически невозможно. Даже библиотека Prototype JS допускает этот недостаток, когда говорит:

"Hash can be thought of as an associative array, binding unique keys to values (which are not necessarily unique)..."

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

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

myObject[myProperty] = ...;

такой же как

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

Это необходимо как в JavaScript

myObject["someProperty"]

такой же как

myObject.someProperty

И да, мне тоже грустно :-(

Самый простой способ сделать это - дать каждому из ваших объектов собственный уникальный метод 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> в свой хеш, иначе она сотрет запись для вашего выходящего объекта с этим идентификатором.

Теперь все мои хэши совершенно холодные. Я также только что опубликовал запись в блоге несколько дней назад о именно эта тема.

Но это упускает из виду главное. В Java есть equals() и hashCode(), так что два эквивалентных объекта имеют одинаковое хеш-значение. Использование вышеупомянутого метода означает, что каждый экземпляр MyObject будет иметь уникальную строку, а это означает, что вам нужно будет сохранить ссылку на этот объект, чтобы когда-либо получить правильное значение с карты. Наличие ключа бессмысленно, потому что он не имеет ничего общего с уникальностью объекта. Полезная функция toString() должна быть реализована для конкретного типа объекта, который вы используете в качестве ключа.

sethro 18.01.2014 01:16

@sethro вы можете реализовать toString для объектов таким образом, чтобы он напрямую отображался в отношении эквивалентности, чтобы два объекта создавали одну и ту же строку, если они считаются «равными».

Daniel X Moore 19.01.2014 00:16

Верно, и это правильный способ Только использовать toString(), чтобы вы могли использовать Object как Set. Думаю, я неправильно понял ваш ответ как попытку предоставить общее решение, чтобы избежать написания эквивалента toString() для equals() или hashCode() в каждом конкретном случае.

sethro 23.01.2014 22:07

Дауотс. Это не хэш-код, см. Мои ответы на: stackoverflow.com/a/14953738/524126 И настоящая реализация хэш-кода: stackoverflow.com/a/15868654/524126

Metalstorm 26.04.2014 20:37

@Metalstorm вопрос не о "истинном" хэш-коде, а скорее о том, как успешно использовать объект как набор в JavaScript.

Daniel X Moore 26.04.2014 21:42

@Daniel X Moore. А чтобы сделать это для объектов, вам нужно сгенерировать хэш-код, 2 объекта (разные ссылки) с одинаковым внутренним состоянием не должны быть в наборе, и это то, что защищает хэш-код. Обычно это можно сделать проще с помощью UUID.

Metalstorm 26.04.2014 22:57

А что, если ваши объекты являются элементами DOM? Затем вам нужно переопределить множество вещей, которые вы не хотели бы переопределять ...

Michael 28.05.2014 03:22

Решение, которое я выбрал, похоже на решение Дэниела, но вместо того, чтобы использовать фабрику объектов и переопределить toString, я явно добавляю хэш к объекту, когда он впервые запрашивается с помощью функции getHashCode. Немного грязно, но лучше для моих нужд :)

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

Если вы хотите пойти по этому пути, гораздо лучше установить hashCode через Object.defineProperty с enumerable, установленным на false, чтобы вы не нарушили цикл for .. in.

Sebastian Nowak 07.08.2014 17:36

Если вам нужна функция 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() вместе с этой функцией.

это создает -hash, не идеально

qodeninja 14.09.2012 04:15

@KimKha char - зарезервированное слово в JS и может вызвать некоторые проблемы. Было бы лучше другое имя.

szeryf 08.02.2013 23:28

хеши @szeryf обычно положительные

qodeninja 12.02.2013 20:45

@qodeninja говорит, кто? Впервые слышу подобное заявление. Можно ссылку на какой-нибудь источник? Хеши обычно вычисляются с использованием целочисленных арифметических и битовых операций фиксированного размера, поэтому можно ожидать положительных или отрицательных результатов.

szeryf 14.02.2013 22:26

Придирчиво, но ... "if (this.length == 0) return hash;" избыточно :) И лично поменял бы "символ" на "код".

Metalstorm 14.07.2013 03:43

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

Jim Pivarski 11.02.2014 00:20

Когда он возвращает отрицательный хэш, просто используйте Math.abs.

user11534547 14.04.2020 13:24

Предупреждение: "hello".hashCode() почти такой же, как "hellp".hashCode(), обычно это то, что мы не хотим для хеша ... К сожалению, это плохой рецепт, который снова и снова копируется во многих ответах SO ...

Basj 09.06.2020 18:21

@Basj ожидается, что хэш-код дублируется. Следовательно, использование hashCode в большинстве случаев не рекомендуется, но я написал его здесь на случай, если кому-то это понадобится. Итак, сделайте свой выбор.

KimKha 10.06.2020 03:33

Также обратите внимание, что ответ основан на функции Java hashCode, которая тоже может дублировать, docs.oracle.com/javase/7/docs/api/java/lang/…

KimKha 10.06.2020 03:34

То, что вы описали, охватывается 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

WeakMaps доступны в текущих версиях Firefox, Chrome и Edge. Они также поддерживаются в Node v7 и в v6 с флагом --harmony-weak-maps.

В чем разница между ними и Map?

smac89 11.07.2017 06:47

@ smac89 WeakMap имеет ограничения: 1) Принимает только объекты в качестве ключей 2) Нет свойства размера 3) Нет итератора или метода forEach 4) Нет четкого метода. Ключ - это объект - поэтому, когда объект будет удален из памяти, данные из WeakMap, связанные с этим объектом, также будут удалены. Это очень полезно, когда мы хотим сохранить информацию, которая должна существовать только пока существует объект. Итак, WeakMap имеет только методы: установить, удалить для записи и получить, имеет для чтения

Ekaterina Tokareva 27.08.2017 15:35

Это работает не совсем правильно ... var m = new Map();m.set({},"abc"); console.info(m.get({}) //=>undefined Это работает, только если у вас есть та же самая переменная, на которую вы изначально ссылались в команде set. НАПРИМЕР. var m = new Map();a = {};m.set(a,"abc"); console.info(m.get(a) //=>undefined

Sancarn 04.09.2018 19:51

@Sancarn Это не обязательно должна быть одна и та же переменная, но они должны указывать на один и тот же объект. В вашем первом примере у вас есть два разных объекта, они выглядят одинаково, но имеют разные адреса.

Svish 21.11.2019 13:47

@Svish хорошее место! Хотя я знаю это сейчас, возможно, тогда я бы этого не сделал :)

Sancarn 21.11.2019 14:38

В дополнение к ответу на отсутствие век, вот функция, которая возвращает воспроизводимый уникальный идентификатор для любого объекта:

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

Как видите, он использует список для поиска, что очень неэффективно, однако это лучшее, что я смог найти на данный момент.

Если вы хотите использовать объекты в качестве ключей, вам необходимо перезаписать их метод toString, как уже упоминалось здесь. Все использованные хеш-функции хороши, но они работают только для одних и тех же объектов, а не для одинаковых объектов.

Я написал небольшую библиотеку, которая создает хэши из объектов, которые вы можете легко использовать для этой цели. Объекты даже могут иметь разный порядок, хеши будут одинаковыми. Внутри вы можете использовать разные типы для своего хэша (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.info(foo[{bar: 'foo'}]);
console.info(foo[{}]);

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

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

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

(function() {
    var lastStorageId = 0;

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

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

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

Я думаю, что это более удобно с другими функциями манипулирования объектами в JavaScript.

Объекты с одинаковыми внутренними значениями будут хешироваться в разные хеши, это не то, что делает хеш (код).

Metalstorm 25.04.2014 21:44

В JavaScript (и я думаю, что почти во всех других языках) два объекта, созданные с одинаковыми внутренними значениями, по-прежнему являются разными объектами, потому что каждый из них представляет собой новый экземпляр объекта. jsfiddle.net/h4G9f

Johnny 25.04.2014 23:56

Да, но хэш-код не для этого, хэш-коды используются для проверки равенства состояния объектов. Как и в случае с хешем, входят одни и те же входные данные (значения переменных), выходит тот же хеш. То, что вы ищете, - это UUID (который предоставляет ваша функция).

Metalstorm 26.04.2014 02:15

Ты прав. Я неправильно понял вопрос. На самом деле плохо, что принятый ответ тоже не является хорошим решением.

Johnny 26.04.2014 16:05

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

Metalstorm 26.04.2014 20:32

Не стесняйтесь изменить код в моем ответе соответственно.

Johnny 28.04.2014 12:41

Некоторое время назад я собрал небольшой модуль JavaScript для создания хэш-кодов для строк, объектов, массивов и т. д. (Я просто передал его в GitHub :))

Использование:

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

Разве сборщик мусора javascript не задыхается от циклических ссылок?

Clayton Rabenda 03.07.2013 01:43

@Ryan Long Я могу пойти дальше и сказать, что если у вас есть циклические ссылки, вам нужно реорганизовать свой код;)

Metalstorm 25.04.2014 21:50

@Metalstorm "тогда тебе нужно реорганизовать свой код" Ты шутишь? Каждая пара родительских и дочерних элементов DOM представляет собой циклическую ссылку.

Chris Middleton 04.01.2015 16:49

Он плохо выполняет хеширование объектов, которые имеют числовые свойства, во многих случаях возвращая одно и то же значение, т.е. var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.info(hash1, hash2); будет регистрировать 28678741732867874173

Julien Bérubé 17.03.2015 19:35

В моей конкретной ситуации меня волнует только равенство объекта в том, что касается ключей и примитивных значений. Решение, которое сработало для меня, заключалось в преобразовании объекта в его представление 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
// }

В ECMAScript 6 теперь есть Set, который работает так, как вы хотите: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

Он уже доступен в последних версиях Chrome, FF и IE11.

Это должен быть главный ответ в 2016 году. Если вы используете Babel, вы можете использовать Set в соответствии со спецификацией ES6, и он будет автоматически полифилен на выходе ES5. babeljs.io/docs/learn-es2015/#map-set-weak-map-weak-set

atroberts20 02.12.2016 20:47

Если вы хотите иметь уникальные значения в объекте поиска, вы можете сделать что-то вроде этого:

Создание объекта поиска

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 27.09.2017 06:50

@tuxSlayer Спасибо, что сообщили мне. Вы можете легко расширить этот код под свои нужды, но я надеюсь, что идея несколько ясна :)

A1rPun 27.09.2017 18:09

Это приведет к созданию очень длинных ключей для больших объектов, которые могут сильно ударить по памяти и производительности.

Gershy 26.12.2017 01:46

Ссылка: 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';

За исключением того, что на самом деле нет способа восстановить символ let x = Symbol ('a'); let y = Symbol ('a'); console.info (x === y); пусть y = символ ('a'); console.info (x === y); // возвращает false Значит, Symbol не работает как хеш.

Richard Collette 14.11.2019 01:13

Вот мое простое решение, которое возвращает уникальное целое число.

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

Сложность этого подрывает всю идею hashCode ()

tuxSlayer 27.09.2017 06:47

Я не считаю это слишком сложным. Однако мне было любопытно: почему именно фаза замены? В противном случае исключения на charCodeAt вернулись бы нормально, не так ли?

Greg Pettit 19.08.2019 20:13

Жаль из-за hashcode({a:1, b:2}) === hashcode({a:2, b:1}) и многих других конфликтов.

maaartinus 31.03.2020 02:52

Я постараюсь пойти немного глубже, чем другие ответы.

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

Одна проблема связана с термином хэш / хэш-код ... есть криптографическое хеширование и некриптографическое хеширование. Другая проблема заключается в том, что вы должны понимать, почему хеширование полезно и как оно работает.

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

Это зависит от того, какие данные у вас есть и чего вы хотите достичь.

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

  • Хеш целого числа - это ... целое число, так как оно уникально, вам повезло!
  • Хеш строки ... это зависит от строки, если строка представляет собой уникальный идентификатор, вы можете рассматривать его как хеш (поэтому хеширование не требуется).
  • Все, что косвенно является в значительной степени уникальным целым числом, является простейшим случаем.
  • Это будет учитывать: хэш-код равен, если объекты равны

Ваши данные обладают некоторой естественной "составной" уникальностью:

  • Например, с объектом человека вы можете вычислить хэш, используя имя, фамилию, дату рождения, ... посмотрите, как это делает Java: Хорошая хеш-функция для строк, или используйте другую информацию идентификатора, которая является дешевой и достаточно уникальной для вашего варианта использования.

Вы не представляете, какими будут ваши данные:

  • Удачи ... вы можете сериализовать в строку и хешировать ее в стиле Java, но это может быть дорого, если строка большая и она не избежит коллизий, а также скажет хеш целого числа (self).

Не существует магически эффективной техники хеширования для неизвестных данных, в некоторых случаях это довольно просто, в других случаях вам, возможно, придется дважды подумать. Таким образом, даже если JavaScript / ECMAScript добавит дополнительную поддержку, для этой проблемы не существует волшебного языкового решения.

На практике нужно две вещи: достаточная уникальность, достаточная скорость.

В дополнение к этому было бы здорово иметь: «хэш-код равен, если объекты равны»

Я объединил ответы от без век и KimKha.

Ниже представлен сервис 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"}'});

Это вернет

[]

Основываясь на заголовке, мы можем генерировать сильные хэши SHA, в контексте браузера его можно использовать для генерации уникального хэша из объекта, массива параметров, строки или чего-то еще.

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.info(hashHex)
}

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

Вышеупомянутый вывод в моем браузере должен быть одинаковым для вас:

bf1cf3fe6975fe382ab392ec1dd42009380614be03d489f23601c11413cfca2b
93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588
d2f209e194045604a3b15bdfd7502898a0e848e4603c5a818bd01da69c00ad19

Поддерживаемые алгоритмы:

SHA-1 (but don't use this in cryptographic applications)
SHA-256
SHA-384
SHA-512

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

Обратите внимание, что это будет работать только для HTTPS. В спецификации для WebCrypto явно указано, что webcrypto - это undefined в небезопасных контекстах (также известный как http).

Gautham C. 11.03.2021 20:01

Просто используйте скрытое секретное свойство с definePropertyenumerable: false

Работает очень быстро:

  • Уникальный идентификатор первого чтения: 1,257,500 операций / с
  • Все остальные: 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
}

Другие вопросы по теме