如何基于JavaScript对象生成唯一键/哈希?解决属性顺序影响问题
解决对象生成唯一缓存键的问题(忽略属性顺序)
你遇到的问题是JSON.stringify()会因为对象属性顺序不同生成不同字符串,导致obj1和obj2无法生成相同的缓存键。下面给你两种方案,分别适配原始类型和嵌套非原始类型的场景:
方案一:仅处理原始类型属性
核心思路是先把对象的键排序,再按排序后的顺序拼接键值对,这样不管属性顺序如何,只要键值完全匹配,生成的键就一致。
function createCacheKey(obj) { // 提取所有键并按字母排序 const sortedKeys = Object.keys(obj).sort(); // 拼接排序后的键和对应值的序列化字符串 return sortedKeys.map(key => `${key}:${JSON.stringify(obj[key])}`).join('|'); } // 测试示例 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' }; console.log(createCacheKey(obj1)); // 输出:key1:"str1"|key2:"str2" console.log(createCacheKey(obj2)); // 和obj1结果完全一致 console.log(createCacheKey(obj3)); // 输出:key1:"something else"|key2:"str2" console.log(createCacheKey(obj4)); // 输出:differentKey:"str1"|key2:"str2"
这个方法简单直接,适合属性值都是字符串、数字、布尔、null这类原始类型的场景。
方案二:支持嵌套非原始类型(对象、数组)
如果你的对象里有嵌套的对象或数组,需要递归处理嵌套结构,确保嵌套对象的键也被排序后序列化:
function deepCreateCacheKey(obj, visited = new WeakSet()) { // 处理原始类型 if (obj === null || typeof obj !== 'object') { return JSON.stringify(obj); } // 处理循环引用(避免无限递归) if (visited.has(obj)) { return '[Circular]'; } visited.add(obj); if (Array.isArray(obj)) { // 数组按元素顺序递归处理 const items = obj.map(item => deepCreateCacheKey(item, visited)).join(','); visited.delete(obj); return `[${items}]`; } // 对象按键排序后递归处理每个值 const sortedKeys = Object.keys(obj).sort(); const entries = sortedKeys.map(key => `"${key}":${deepCreateCacheKey(obj[key], visited)}`).join(','); visited.delete(obj); return `{${entries}}`; } // 测试嵌套对象 const obj5 = { key2: { b: 2, a: 1 }, key1: 'str1' }; const obj6 = { key1: 'str1', key2: { a: 1, b: 2 } }; console.log(deepCreateCacheKey(obj5)); // 和obj6生成的键完全一致
这个方法能处理多层嵌套的对象和数组,还加了循环引用的检测,避免递归死循环。
额外注意点
- 如果对象里包含函数、Symbol类型,
JSON.stringify()会忽略函数,Symbol作为键也会被过滤掉。如果需要支持这类类型,可以额外处理:比如把函数转为obj[key].toString(),Symbol键转为Symbol.keyFor(key)或者key.description。 - 对于Date对象,
JSON.stringify()会转为ISO字符串,这个是符合预期的,因为相同时间的Date序列化结果一致。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

