Скажем, у меня есть следующие объекты JavaScript:
const obj1 = {
key1: 'str1',
key2: 'str2'
}
const obj2 = {
key2: 'str2',
key1: 'str1'
}
const obj3 = {
key1: 'something else',
key2: 'str2'
}
const obj4 = {
differentKey: 'str1',
key2: 'str2'
}
Я хотел бы создать уникальный ключ на основе данного объекта. Это сделано для того, чтобы я мог правильно кэшировать некоторые данные, относящиеся к каждому объекту в структуре Map. В этом сценарии obj1 и obj2 должны иметь один и тот же ключ, поскольку единственная разница — это порядок свойств. obj3 и obj4 должны иметь разные ключи. Я пробовал использовать JSON.stringify(), но это дает разные результаты для obj1 и obj2 из-за порядка. Есть ли способ обойти это?
Я приму ответ, который обрабатывает только примитивные типы, но и ответ, который обрабатывает не примитивные типы, также будет принят, и это было бы здорово!
Если JSON.stringify для вас приемлемо, это звучит так, будто длина «ключа» не вызывает беспокойства, в то время как вероятность столкновения даже в одну триллионную долю? И какие это могут быть свойства? Например, создание ключа для свойств символа кажется настоящей проблемой (невозможной?).
@mykaf Это кажется ненужным; его легко воспроизвести, вызвав JSON.stringify для любых двух объектов с ключами в разном порядке.
@MarkBaijens Это похоже, но не отвечает, как сгенерировать хеш для объекта, игнорируя порядок ключей. Задавший не должен отвечать за то, чтобы отличать свой вопрос от любого другого аналогичного вопроса в Stack Overflow.
сложность ответа зависит от сложности реальных объектов, с которыми вам придется иметь дело. Тривиальные примеры в вопросе легко обрабатываются.
@Unmitigated Насколько я понимаю, ОП пытается решить проблему сравнения объектов в Javascript. Он предполагает, что хеш может быть одним из способов решения этой проблемы. Однако я не думаю, что хэш будет полезен для понимания того, как работают объекты. Поэтому дубликат, на мой взгляд, очень подходит.
@MarkBaijens В вопросе упоминаются только данные кэширования, связанные с объектами, например. в структуре хэш-карты. Если вы не предложите сравнить ключ с любым другим ключом на карте, это не даст полного ответа на вопрос.
Для преобразования любого произвольного объекта в хэш потребуется специальный код для работы с определенными структурами данных. Какие свойства должны способствовать хешу? Чего не должно быть? Какие части графа объекта важны? Как сравнивать функции? Как обращаться с циклами? На этот вопрос нет однозначного ответа, кроме как сказать, что простейший возможный способ различения «ключевых» объектов, вероятно, является хорошей отправной точкой.
Привет всем, спасибо за ваши комментарии! Я хочу уточнить, что я приму ответ, который обрабатывает только примитивные типы в плоском объекте. Однако я не хотел никого отговаривать от публикации решения, которое обрабатывает более сложные типы, такие как функции или вложенные структуры.
Чтобы ответить @Unmitigated, да, мне нужен ключ, который я могу использовать в экземпляре Map.
@Matt Это разъяснение следует включить в сам вопрос.
@MarkBaijens «Однако я не думаю, что хеш будет полезен для понимания того, как работают объекты. Поэтому, на мой взгляд, дубликат очень подходит». вы просто пытаетесь ответить на другой вопрос, отличный от заданного. Если вы не знаете, попросите разъяснений. И считайте закрытие неясным, если на него действительно нельзя ответить. Однако не закрывайте вопрос об А просто как о Б. Если будущий посетитель будет искать, как хешировать объект (А), ему не будет предложено узнать, как сравнивать объекты (Б). Принимая решение в пользу ОП, вы также утверждаете, что все запросы об А на самом деле касаются Б.



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


Я думаю, вы могли бы преобразовать свои объекты в массив, отсортировать его по ключам и повторно привести к исходному типу объекта. Тогда у вас будет тот же порядок ключей, и вы сможете приступить к хешированию.
Здесь более развернутый ответ на аналогичный вопрос (написанный не мной) https://stackoverflow.com/a/1069840/20932276
Вы не можете надежно «привести» объект к массиву; вы, конечно, можете реализовать что-то, что преобразует определенные типы объектов, важных для конкретного приложения, но в целом эта концепция не имеет смысла.
Вот функция, которая рекурсивно сортирует вложенные объекты по ключу. Затем вы можете использовать JSON.stringify для создания уникальных ключей.
Не стесняйтесь настраивать проверку типа объекта (isObject) в соответствии с вашими потребностями.
Обновлено: Как упоминал VLAZ, JSON.stringify может исключать определенные типы значений. А именно функция, символ или неопределенное. Я обновил пример для обработки undefined, и при необходимости вы можете расширить функцию replacer для обработки функций и символов.
function sort(object) {
const sortedEntries = Object.entries(object).sort((a, b) =>
a[0].localeCompare(b[0])
);
const withSortedValues = sortedEntries.map(([key, value]) => {
const isObject = typeof value === 'object' && value !== null
const newVal = isObject ? sort(value) : value;
return [key, newVal];
});
return Object.fromEntries(withSortedValues);
}
// Edit: Replacer function to keep undefined values
// and replace them with a placeholder. Feel free to
// change the placeholder to your needs (another string or null)
function replacer(k,v) {
return v === undefined ? "[undefined]" : v;
}
function compare(obj1, obj2) {
return JSON.stringify(sort(obj1), replacer) === JSON.stringify(sort(obj2), replacer);
}
const obj1 = {
a: 1,
b: { c: 1, d: 2 },
};
const obj2 = {
b: { d: 2, c: 1 },
a: 1,
};
const obj3 = {
b: { d: 4, c: 3 },
a: 1,
};
const obj4 = {
a: 1,
b: { c: 1, d: 2},
c: undefined
}
console.info('1 == 2', compare(obj1, obj2)); // true
console.info('1 == 3', compare(obj1, obj3)); // false
// Edit: Handling a normally excluded value tyoe, i.e. undefined
console.info('1 == 4', compare(obj1, obj4)); // falseJSON.stringify не является надежным решением. При сериализации будут пропущены некоторые ключи вместе с их ключом. Рассмотрим compare( { a: 1, b: 2 }, { a: 1, b: 2, c: undefined }); (демо)
Это хороший момент, и его важно иметь в виду. Является ли это препятствием или нет, в конечном итоге будет зависеть от варианта использования OP и способа создания объекта.
@VLAZ Я обновил ответ, чтобы обрабатывать значения undefined. JSON.stringify также исключим функции и символы, но оставлю это подразумеваемым. до ОП и их потребностей.
Это работает. Я не рассматривал возможность просто поставить JSON.stringify() и рассортировать объект. Спасибо!
Пожалуйста, поделитесь своей попыткой, используя
JSON.stringify()