JavaScript如何比较Map的key

sulc1iza  于 2024-01-05  发布在  Java
关注(0)|答案(4)|浏览(138)

我在一个node.js应用程序中使用JavaScript ES6功能:

class pairKey {
constructor(x_pos, y_pos) {
    this._X = x_pos;
    this._Y = y_pos;
}

get x() {
    return this._X;
}
set x(x_pos) {
    this._X = x_pos;
}

get y() {
    return this._Y;
}
set y(y_pos) {
    this._Y = y_pos;
}

var allElem = new Map();
allElem.set(new pairKey(1,2), 'a');
allElem.set(new pairKey(2,3), 'b');

console.log(allElem.has(new pairKey(1,2))); //Should return true instead return false

字符串
在这段代码中,我想使用一对Int作为我的map(allElem)的键。
问题是我不知道Map在JavaScript中如何比较对象。
有人能帮我吗?

zfycwa2u

zfycwa2u1#

Map使用 SameValueZero 算法来比较键。这意味着引用相等用于对象,所以如果你有a = new PairKey(1, 2)b = new PairKey(1, 2),它们不是同一个对象-a !== b
那么你能做些什么来解决这个问题呢?基本上有两种方法来解决这个问题:

  • 不使用对象本身作为键,而是使用它的原语(例如字符串)表示,它可以从具有相同值的不同示例创建
  • 使用hash consing作为键对象,这样new PairKey在使用相同参数调用时总是返回相同的对象

你也可以继承Map,所有的方法都被覆盖,这样它们就可以专门处理PairKey,依赖于上面的一种技术。
不幸的是,散列consing不可能在没有弱引用和不泄漏内存的情况下实现,所以我们必须求助于第一种技术:

class Pair {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    toKey() {
        return `Pair(${this.x}, ${this.y})`;
    }
    static key(x, y) {
        return new Pair(x, y).toKey();
    }
}

var allElem = new Map(); // string -> string
allElem.set(Pair.key(1, 2), 'a');
allElem.set(Pair.key(2, 3), 'b');

console.log(allElem.has(Pair.key(1, 2))); // true

字符串

fcwjkofz

fcwjkofz2#

代码失败的原因是Map使用同值算法来匹配键。一个对象示例与另一个对象示例的值不同,即使两者共享相同的内在值(例如,try ({a:1} === {a:1})-> it's false)。一种方法是为对象添加一个键属性,使相同的内部值生成完全相同的键(1到1)。然后在设置Map条目时使用该键。参见示例(利用Symbol.for生成可再现键):

'use strict'
class pairKey {
  constructor(x_pos, y_pos) {
    this._X = x_pos;
    this._Y = y_pos;
  }

  get x() {
    return this._X;
  }
  set x(x_pos) {
    this._X = x_pos;
  }

  get y() {
    return this._Y;
  }
  set y(y_pos) {
    this._Y = y_pos;
  }

  get key() {
    return Symbol.for(`pairKey[${this.x}:${this.y}]`);
  }
}
var allElem = new Map();
allElem.set(new pairKey(1, 2).key, 'a');
allElem.set(new pairKey(2, 3).key, 'b');

console.log(allElem.has(new pairKey(1, 2).key));

字符串

c9qzyr3d

c9qzyr3d3#

你的map键是一个对象。console.log返回false,因为你正在创建一个新对象来检索它们的键。它是否具有相同的对并不重要。重要的是它是一个不同的新对象。
如果你想检索对应于new pairKey(1,2)的值,你必须执行以下操作:

let key = new pairKey(1,2);
allElem.set(key, 'a');

console.log(allElem.has(key));

字符串
换句话说,如果使用object作为键,请确保使用相同的对象来检索值。

kninwzqo

kninwzqo4#

我很抱歉提出了这个老问题,但我发现了一个非常有趣的解决方案,灵感来自Bergi's answerhash consing被认为是不可能的。

class PairKey {
  private static cache: Record<string, PairKey> = {};

  constructor(
    private _x: number, private _y: number,
    action: 'create' | 'read' | 'delete' = 'read'
  ) {
      const key = PairKey.key(_x, _y);

      if (action === 'create' || action === 'read') {
        if (PairKey.cache[key]) {
            return PairKey.cache[key];
        }
        if (action === 'create') {
          PairKey.cache[key] = this;
        }
      }
      else if (action === 'delete') {
        delete PairKey.cache[key];
      }
  }

  private static key(x: number, y: number) {
      return `${x}_${y}`;
  }

  get x() {
      return this._x;
  }

  set x(x_pos: number) {
      this._x = x_pos;
  }

  get y() {
      return this._y;
  }

  set y(y_pos: number) {
      this._y = y_pos;
  }
}

const allElem = new Map<PairKey, string>();

allElem.set(new PairKey(1, 2, 'create'), 'a');  // the action flag to prevent a memory leak

allElem.set(new PairKey(2, 3, 'create'), 'b');  // the action flag to prevent a memory leak

console.log(allElem.has(new PairKey(1, 2))); // Returns true

allElem.delete(new PairKey(1, 2, 'delete'));  // the action flag to prevent a memory leak

console.log(allElem.has(new PairKey(1, 2))); // Returns false

字符串
一个类似的解决方案,更多的静态的东西:

class PairKey {
  private static cache: Record<string, PairKey> = {};
  private static readonly symbol = Symbol();

  private constructor(private _x: number, private _y: number, symbol: symbol) {
    if (symbol !== PairKey.symbol) {
      throw new Error("Use 'PairKey.create()' instead of constructor");
    }
  }

  static create(x: number, y: number) {
    const key = PairKey.key(x, y);

    if (PairKey.cache[key]) {
      return PairKey.cache[key];
    }

    const pairKey = new PairKey(x, y, PairKey.symbol);
    PairKey.cache[key] = pairKey;
    return pairKey;
  }

  static read(x: number, y: number) {
    const key = PairKey.key(x, y);
    return PairKey.cache[key];
  }

  static delete(x: number, y: number) {
    const key = PairKey.key(x, y);
    const pairKey = PairKey.cache[key];
    delete PairKey.cache[key];
    return pairKey;
  }

  private static key(x: number, y: number) {
    return `${x}_${y}`;
  }

  get x() {
    return this._x;
  }

  set x(x_pos: number) {
    this._x = x_pos;
  }

  get y() {
    return this._y;
  }

  set y(y_pos: number) {
    this._y = y_pos;
  }
}

const allElem = new Map<PairKey, string>();

allElem.set(PairKey.create(1, 2), 'a');
allElem.set(PairKey.create(2, 3), 'b');

console.log(allElem.has(PairKey.read(1, 2))); // Returns true

allElem.delete(PairKey.delete(1, 2));

console.log(allElem.has(PairKey.read(1, 2))); // Returns false

相关问题