【问题标题】:How Javascript compare key of MapJavascript如何比较Map的键
【发布时间】:2015-08-11 19:59:55
【问题描述】:

我在 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 中的对象。
有人可以帮助我吗?

【问题讨论】:

    标签: javascript dictionary ecmascript-6


    【解决方案1】:

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

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

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

    您还可以将Map 子类化,其中所有方法都被覆盖,以便它们专门处理PairKeys,依赖于上述技术之一。

    不幸的是,如果没有弱引用和内存泄漏,hash 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
    

    【讨论】:

      【解决方案2】:

      您的代码失败的原因是 Map 使用相同值算法来匹配键。一个对象实例与另一个对象实例的值不同,即使它们共享相同的内在值(例如,尝试({a:1} === {a:1}) -> 它是错误的)。一种可以为您工作的方法是向您的对象添加一个键属性,以便相同的内在值生成完全相同的键(1 到 1)。然后在设置地图条目时使用该键。查看示例(利用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));

      【讨论】:

      • 在这里使用Symbol.for 与使用字符串相比有什么好处?
      • @StefanMonov 5 多年前这似乎是有道理的:-D
      【解决方案3】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-27
        • 2019-04-20
        • 1970-01-01
        • 1970-01-01
        • 2020-08-23
        • 2016-11-09
        相关资源
        最近更新 更多