You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript Map对象键按值匹配及无序值对键实现方法咨询

实现按值匹配的Map及无序键Map方案

原生Map对对象类型的键采用SameValueZero比较规则,仅比较对象的内存引用地址,两个独立创建、结构完全相同的对象会被判定为不同的键,因此会出现你遇到的生成2个元素的问题,可通过以下方案实现按实际值匹配的Map:

方案1:序列化键实现(性能优先)

核心思路是将对象类型的键序列化为稳定的字符串,利用原生Map对原始值的等值比较能力实现按值匹配,序列化时对对象键做排序处理,天然支持无序对象键的匹配。

class ValueMap extends Map {
  // 私有方法:稳定序列化键
  #serializeKey(key) {
    // 非对象类型和null直接返回原始值
    if (typeof key !== 'object' || key === null) return key
    // 按对象键的字母序排序后序列化,避免键顺序不同导致序列化结果差异
    return JSON.stringify(key, Object.keys(key).sort())
  }

  set(key, value) {
    const serializedKey = this.#serializeKey(key)
    return super.set(serializedKey, value)
  }

  get(key) {
    const serializedKey = this.#serializeKey(key)
    return super.get(serializedKey)
  }

  has(key) {
    const serializedKey = this.#serializeKey(key)
    return super.has(serializedKey)
  }

  delete(key) {
    const serializedKey = this.#serializeKey(key)
    return super.delete(serializedKey)
  }
}

测试效果:

let a = new ValueMap();
a.set({a: 1, b:3}, "Hello");
a.set({a: 1, b:3}, "World");
console.log(a.size) // 输出1,符合预期
console.log(a.get({b:3, a:1})) // 输出World,键顺序不同也可正常匹配

该方案的优缺点:

  • 优点:性能接近原生Map,适合键数量大的场景
  • 缺点:仅支持可JSON序列化的键,无法处理包含循环引用、函数、Symbol、undefined、BigInt等类型的键

方案2:深比较实现(兼容性优先)

核心思路是存储原始键值对,查找时对所有键做深相等判断,支持所有JS类型的键。

// 简易深相等判断函数,可根据需求扩展支持更多特殊类型
function deepEqual(a, b) {
  if (a === b) return true
  if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) return false
  const keysA = Object.keys(a), keysB = Object.keys(b)
  if (keysA.length !== keysB.length) return false
  for (const key of keysA) {
    if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false
  }
  return true
}

class DeepCompareMap {
  #entries = []

  set(key, value) {
    const existingIndex = this.#entries.findIndex(([k]) => deepEqual(k, key))
    if (existingIndex > -1) {
      this.#entries[existingIndex][1] = value
    } else {
      this.#entries.push([key, value])
    }
    return this
  }

  get(key) {
    const entry = this.#entries.find(([k]) => deepEqual(k, key))
    return entry ? entry[1] : undefined
  }

  has(key) {
    return this.#entries.some(([k]) => deepEqual(k, key))
  }

  delete(key) {
    const existingIndex = this.#entries.findIndex(([k]) => deepEqual(k, key))
    if (existingIndex > -1) {
      this.#entries.splice(existingIndex, 1)
      return true
    }
    return false
  }

  get size() {
    return this.#entries.length
  }
}

该方案的优缺点:

  • 优点:支持所有JS类型的键,可处理复杂结构、循环引用等特殊场景
  • 缺点:查找、插入的时间复杂度为O(n),键数量较多时性能较差,适合键数量少的场景

无序值对作为键的专用实现

如果你的键是固定长度为2的无序值对(如[a,b]和[b,a]要判定为同一个键),可以单独做标准化处理:

class PairMap extends Map {
  #normalizePair(pair) {
    if (!Array.isArray(pair) || pair.length !== 2) throw new Error('键必须是长度为2的数组')
    // 对值对做稳定排序,保证顺序不同的同值对得到的键相同
    return pair.sort().join(',')
    // 如果值对包含对象,可结合前面的序列化/深比较逻辑处理
  }

  set(pair, value) {
    return super.set(this.#normalizePair(pair), value)
  }

  get(pair) {
    return super.get(this.#normalizePair(pair))
  }

  has(pair) {
    return super.has(this.#normalizePair(pair))
  }

  delete(pair) {
    return super.delete(this.#normalizePair(pair))
  }
}

// 测试效果
const m = new PairMap()
m.set([1,2], 'test')
console.log(m.get([2,1])) // 输出test

内容的提问来源于stack exchange,提问作者Davo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 07:09:03