Javascript如何比较Map的关键

时间:2015-08-11 19:59:56

标签: javascript dictionary ecmascript-6

我在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作为我的地图的关键字(allElem)。
问题是我不知道Map如何比较javascript中的对象 有人可以帮帮我吗?

3 个答案:

答案 0 :(得分:4)

Map确实使用SameValueZero algorithm来比较密钥。这意味着引用相等用于对象,因此如果您有a = new PairKey(1, 2)b = new PairKey(1, 2),则它们不是同一个对象 - a !== b

那么你能做些什么来解决这个问题呢?基本上有两种解决方法:

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

此外,您可以将Map子类化为覆盖所有方法的所有方法,以便他们专门处理PairKey,依赖于上述技术之一。

不幸的是,如果没有弱引用并且没有泄漏内存,就不可能实现哈希值,所以我们不得不求助于第一种技术:

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

答案 1 :(得分:3)

您的代码失败的原因是Map使用相同值算法来匹配键。对象实例与另一个对象实例的值不同,即使两者共享相同的内在值(例如,尝试({a:1} === {a:1}) - >它是假的)。您可以使用的一种方法是向对象添加一个键属性,以便相同的内部值生成完全相同的键(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));

答案 2 :(得分:0)

您的地图密钥是一个对象。 console.log会返回false,因为您正在创建一个新对象来检索它们的密钥。它有同一对并不重要。重要的是它是一个不同的新对象。

如果要检索与new pairKey(1,2)对应的值,则必须执行以下操作:

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

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

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