В основном я пытаюсь создать объект из уникальных предметов, набор. У меня возникла блестящая идея просто использовать объект JavaScript с объектами для имен свойств. Такие как,
set[obj] = true;
Это работает до определенной степени. Он отлично работает со строками и числами, но с другими объектами кажется, что все они «хешируют» одно и то же значение и обращаются к одному и тому же свойству. Есть ли способ сгенерировать уникальное хеш-значение для объекта? Как это делают строки и числа, могу ли я отменить то же поведение?
JSON.stringify(obj) или obj.toSource() могут работать для вас в зависимости от проблемы и целевой платформы.
@Annan JSON.stringify (obj) буквально просто преобразует (весь) объект в строку. Таким образом, вы просто копируете объект на себя. Это бессмысленно, бесполезно и неоптимально.
@Metalstorm True, поэтому все зависит от вашей проблемы. Когда я нашел этот вопрос через Google, мое окончательное решение вызвало toSource () для объектов. Другой способ - использовать обычный хеш для источника.
@Annan, toSource не работает в Chrome, кстати



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Объекты 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 для объектов, которые вы хотите хэшировать, и который может формировать их хэш-идентификатор.
другой вариант - присвоить каждому объекту случайное значение в качестве хэша - возможно, случайное число + общее количество тиков - а затем иметь набор функций для добавления / удаления объекта из массива.
Это не удастся, если вы добавите один и тот же объект дважды. Он будет думать, что это другое.
«Это не удастся, если вы добавите один и тот же объект дважды. Он будет думать, что это другой». Хорошая точка зрения. Решением может быть подкласс Array для ObjectReference, подключив дублирующую проверку к push (). У меня сейчас нет времени редактировать это решение, но я надеюсь, что вспомню об этом позже.
Мне нравится это решение, потому что оно не требует каких-либо дополнительных свойств в объекте. Но это становится проблематичным, если вы пытаетесь получить чистый сборщик мусора. В вашем подходе он сохранит объект, хотя другие ссылки уже были удалены. Это может привести к проблемам в более крупных приложениях.
Какой смысл хешировать объекты, если каждый раз, когда вы обращаетесь к ним, вам нужно линейное сканирование массива?
Я думал, что объекты JavaScript также могут использовать символы в качестве ключей ...?
Если вы действительно хотите установить поведение (я исхожу из знания 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)..."
Спецификация 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 вы можете реализовать toString для объектов таким образом, чтобы он напрямую отображался в отношении эквивалентности, чтобы два объекта создавали одну и ту же строку, если они считаются «равными».
Верно, и это правильный способ Только использовать toString(), чтобы вы могли использовать Object как Set. Думаю, я неправильно понял ваш ответ как попытку предоставить общее решение, чтобы избежать написания эквивалента toString() для equals() или hashCode() в каждом конкретном случае.
Дауотс. Это не хэш-код, см. Мои ответы на: stackoverflow.com/a/14953738/524126 И настоящая реализация хэш-кода: stackoverflow.com/a/15868654/524126
@Metalstorm вопрос не о "истинном" хэш-коде, а скорее о том, как успешно использовать объект как набор в JavaScript.
@Daniel X Moore. А чтобы сделать это для объектов, вам нужно сгенерировать хэш-код, 2 объекта (разные ссылки) с одинаковым внутренним состоянием не должны быть в наборе, и это то, что защищает хэш-код. Обычно это можно сделать проще с помощью UUID.
А что, если ваши объекты являются элементами DOM? Затем вам нужно переопределить множество вещей, которые вы не хотели бы переопределять ...
Решение, которое я выбрал, похоже на решение Дэниела, но вместо того, чтобы использовать фабрику объектов и переопределить 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.
Если вам нужна функция 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, не идеально
@KimKha char - зарезервированное слово в JS и может вызвать некоторые проблемы. Было бы лучше другое имя.
хеши @szeryf обычно положительные
@qodeninja говорит, кто? Впервые слышу подобное заявление. Можно ссылку на какой-нибудь источник? Хеши обычно вычисляются с использованием целочисленных арифметических и битовых операций фиксированного размера, поэтому можно ожидать положительных или отрицательных результатов.
Придирчиво, но ... "if (this.length == 0) return hash;" избыточно :) И лично поменял бы "символ" на "код".
@qodeninja и @szeryf: вам просто нужно быть осторожным при использовании. Например, я пытался сделать pickOne["helloo".hashCode() % 20] для массива pickOne из 20 элементов. Я получил undefined, потому что хэш-код отрицательный, поэтому это пример, в котором кто-то (я) неявно предполагал положительные хеш-коды.
Когда он возвращает отрицательный хэш, просто используйте Math.abs.
Предупреждение: "hello".hashCode() почти такой же, как "hellp".hashCode(), обычно это то, что мы не хотим для хеша ... К сожалению, это плохой рецепт, который снова и снова копируется во многих ответах SO ...
@Basj ожидается, что хэш-код дублируется. Следовательно, использование hashCode в большинстве случаев не рекомендуется, но я написал его здесь на случай, если кому-то это понадобится. Итак, сделайте свой выбор.
Также обратите внимание, что ответ основан на функции Java hashCode, которая тоже может дублировать, docs.oracle.com/javase/7/docs/api/java/lang/…
То, что вы описали, охватывается 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 WeakMap имеет ограничения: 1) Принимает только объекты в качестве ключей 2) Нет свойства размера 3) Нет итератора или метода forEach 4) Нет четкого метода. Ключ - это объект - поэтому, когда объект будет удален из памяти, данные из WeakMap, связанные с этим объектом, также будут удалены. Это очень полезно, когда мы хотим сохранить информацию, которая должна существовать только пока существует объект. Итак, WeakMap имеет только методы: установить, удалить для записи и получить, имеет для чтения
Это работает не совсем правильно ... 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 Это не обязательно должна быть одна и та же переменная, но они должны указывать на один и тот же объект. В вашем первом примере у вас есть два разных объекта, они выглядят одинаково, но имеют разные адреса.
@Svish хорошее место! Хотя я знаю это сейчас, возможно, тогда я бы этого не сделал :)
В дополнение к ответу на отсутствие век, вот функция, которая возвращает воспроизводимый уникальный идентификатор для любого объекта:
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.
Объекты с одинаковыми внутренними значениями будут хешироваться в разные хеши, это не то, что делает хеш (код).
В JavaScript (и я думаю, что почти во всех других языках) два объекта, созданные с одинаковыми внутренними значениями, по-прежнему являются разными объектами, потому что каждый из них представляет собой новый экземпляр объекта. jsfiddle.net/h4G9f
Да, но хэш-код не для этого, хэш-коды используются для проверки равенства состояния объектов. Как и в случае с хешем, входят одни и те же входные данные (значения переменных), выходит тот же хеш. То, что вы ищете, - это UUID (который предоставляет ваша функция).
Ты прав. Я неправильно понял вопрос. На самом деле плохо, что принятый ответ тоже не является хорошим решением.
Принимая и вашу функцию, я был бы склонен к тому, чтобы это было больше похоже на это: jsfiddle.net/xVSsd Тот же результат, короче (LoC + символы) и, вероятно, немного быстрее :)
Не стесняйтесь изменить код в моем ответе соответственно.
Некоторое время назад я собрал небольшой модуль JavaScript для создания хэш-кодов для строк, объектов, массивов и т. д. (Я просто передал его в GitHub :))
Использование:
Hashcode.value("stackoverflow")
// -2559914341
Hashcode.value({ 'site' : "stackoverflow" })
// -3579752159
Разве сборщик мусора javascript не задыхается от циклических ссылок?
@Ryan Long Я могу пойти дальше и сказать, что если у вас есть циклические ссылки, вам нужно реорганизовать свой код;)
@Metalstorm "тогда тебе нужно реорганизовать свой код" Ты шутишь? Каждая пара родительских и дочерних элементов DOM представляет собой циклическую ссылку.
Он плохо выполняет хеширование объектов, которые имеют числовые свойства, во многих случаях возвращая одно и то же значение, т.е. var hash1 = Hashcode.value({ a: 1, b: 2 }); var hash2 = Hashcode.value({ a: 2, b: 1 }); console.info(hash1, hash2); будет регистрировать 28678741732867874173
В моей конкретной ситуации меня волнует только равенство объекта в том, что касается ключей и примитивных значений. Решение, которое сработало для меня, заключалось в преобразовании объекта в его представление 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
Если вы хотите иметь уникальные значения в объекте поиска, вы можете сделать что-то вроде этого:
Создание объекта поиска
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 Спасибо, что сообщили мне. Вы можете легко расширить этот код под свои нужды, но я надеюсь, что идея несколько ясна :)
Это приведет к созданию очень длинных ключей для больших объектов, которые могут сильно ударить по памяти и производительности.
Ссылка: 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 не работает как хеш.
Вот мое простое решение, которое возвращает уникальное целое число.
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 ()
Я не считаю это слишком сложным. Однако мне было любопытно: почему именно фаза замены? В противном случае исключения на charCodeAt вернулись бы нормально, не так ли?
Жаль из-за hashcode({a:1, b:2}) === hashcode({a:2, b:1}) и многих других конфликтов.
Я постараюсь пойти немного глубже, чем другие ответы.
Даже если бы у JS была лучшая поддержка хеширования, он не мог бы волшебным образом хешировать все идеально, во многих случаях вам придется определять свою собственную хеш-функцию. Например, в Java есть хорошая поддержка хеширования, но вам все равно нужно подумать и поработать.
Одна проблема связана с термином хэш / хэш-код ... есть криптографическое хеширование и некриптографическое хеширование. Другая проблема заключается в том, что вы должны понимать, почему хеширование полезно и как оно работает.
Когда мы говорим о хешировании в JavaScript или Java, большую часть времени мы говорим о некриптографическом хешировании, обычно о хешировании для hashmap / hashtable (если мы не работаем над аутентификацией или паролями, которые вы могли бы делать на стороне сервера с помощью NodeJS. ..).
Это зависит от того, какие данные у вас есть и чего вы хотите достичь.
Ваши данные имеют естественную "простую" уникальность:
Ваши данные обладают некоторой естественной "составной" уникальностью:
Вы не представляете, какими будут ваши данные:
Не существует магически эффективной техники хеширования для неизвестных данных, в некоторых случаях это довольно просто, в других случаях вам, возможно, придется дважды подумать. Таким образом, даже если 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. В спецификации для WebCrypto явно указано, что webcrypto - это undefined в небезопасных контекстах (также известный как http).
Просто используйте скрытое секретное свойство с definePropertyenumerable: false
Работает очень быстро:
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
}
Причина, по которой все объекты имеют одно и то же значение, заключается в том, что вы не переопределили их методы toString. Поскольку ключи должны быть строками, метод toString автоматически вызывается для получения действительного ключа, поэтому все ваши объекты преобразуются в одну и ту же строку по умолчанию: «[object Object]».