如何检查Javascript Map是不是有对象键

Posted

技术标签:

【中文标题】如何检查Javascript Map是不是有对象键【英文标题】:How to check if Javascript Map has an object key如何检查Javascript Map是否有对象键 【发布时间】:2017-12-10 22:20:30 【问题描述】:

查看几个不同的文档,我只看到 Map (ECMAScript6) 键是布尔值、字符串或整数时。有没有办法我们可以使用另一个自定义对象(使用 new CustomObject(x,y) 构造函数调用)作为键添加?

我可以添加一个对象作为键,但无法检查 Map 是否具有所述对象。

var myMap = new Map();
myMap.set( new Tuple(1,1), "foo");
myMap.set('bar', "foo");


myMap.has(?);  
myMap.has('bar');  // returns true

有没有办法解决这个问题?

  var myMap = new Map();
  myMap.set( new Tuple(1,1), "foo");

 for(some conditions) 
 var localData = new Tuple(1,1); //Use directly if exists in myMap? 
 map.has(localData) // returns false as this is a different Tuple object. But I need it to return true

https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Map/has

【问题讨论】:

是的,您可以使用任何对象作为键。但是,它每次都必须是同一个对象——而不仅仅是一个具有相同键和值的对象。嵌套的Map 是实现Tuple 查找的一种选择。 不幸的是,我无法检查它本身是否是同一个对象。它必须是具有一些设置相同的公共属性的对象。有没有办法做到这一点? 作为一名 Java 程序员,Javascript Map 的这些语义令人惊讶和困惑。在 Java 中,我们必须为我们的类提供 equals()hashCode() 方法,然后 Java HashMap 类在使用不同对象但等效对象的键时按预期工作(即,键可以具有 值语义)。 【参考方案1】:

你只需要保存对对象的引用:

var myMap = new Map();
var myKey = new Tuple(1,1);
myMap.set( myKey, "foo");
myMap.set('bar', "foo");

myMap.has(myKey);           // returns true;  myKey === myKey
myMap.has(new Tuple(1,1));  // returns false; new Tuple(1,1) !== myKey
myMap.has('bar');           // returns true;  'bar' === 'bar'

编辑:以下是如何使用对象来实现您想要的,即通过对象的值而不是引用来比较对象:

function Tuple (x, y) 
  this.x = x;
  this.y = y;

Tuple.prototype.toString = function () 
  return 'Tuple [' + this.x + ',' + this.y + ']';
;

var myObject = ;
myObject[new Tuple(1, 1)] = 'foo';
myObject[new Tuple(1, 2)] = 'bar';
console.log(myObject[new Tuple(1, 1)]); // 'foo'
console.log(myObject[new Tuple(1, 2)]); // 'bar'

这些操作平均会在恒定时间内运行,这比在线性时间内通过 Map 搜索相似的对象键要快得多。

【讨论】:

谢谢。不幸的是,我不能对对象使用相同的 myKey 引用。我正在检查具有相同属性集的对象。有什么办法可以解决这个问题。 @LoserCoder 是的,为您的类创建一个 toString() 方法,该方法为具有相同值的实例生成相同的字符串,然后将这些字符串用作对象中的键(那样你就不用甚至必须使用地图)。这就是地图和对象比较在 JS 中的工作方式——对象通过引用进行比较。 @LoserCoder 我添加了一个例子来说明我的意思。这种方法由您自己决定,以确保您的 toString 方法能够准确地序列化您的值对象以进行比较。仅仅因为两个对象是使用相同的构造函数和参数创建的,并不意味着它们一定是等价的。【参考方案2】:

当你给map设置一个对象时,你需要在检查map是否有它的时候传递相同的内存引用。

例子:

const map = new Map();

map.set(new Tuple(1,1));
map.has(new Tuple(1,1)) // False. You are checking a new object, not the same as the one you set.

const myObject = new Tuple(1,1);
map.set(myObject);
map.has(myObject) // True. You are checking the same object.

编辑

如果你真的必须这样做,你可以这样做:

function checkSameObjKey(map, key) 
    const keys = map.keys();
    let anotherKey;

    while(anotherKey = keys.next().value) 
         // YOUR COMPARISON HERE
         if (key.id == anotherKey.id) return true;
    

    return false;


const map = new Map();
map.set(id: 1, 1);

checkSameObjKey(map, id: 1); // True
checkSameObjKey(map, id: 2); // False

【讨论】:

是的,但我正在寻找是否有已知的解决方法。或者我根本不应该在这种情况下使用 Set/Map。如果是这样,我可能不得不直接使用对象引用,但这会导致同样的问题。 用可能的解决方法编辑了我的答案。 @LoserCoder 请注意,此方法使用线性查找,其运行速度比使用 JavaScript 引擎内置的对象键解析算法(哈希表)慢得多,平均时间是恒定的。

以上是关于如何检查Javascript Map是不是有对象键的主要内容,如果未能解决你的问题,请参考以下文章

检查 JavaScript 对象中是不是存在键?

如何检查一个对象是不是至少包含一个键,其值包含 JavaScript 中的子字符串?

如何检查Map中是不是存在键或值?

检查Javascript中对象数组中的键是不是?

如何在不插入的情况下检查 std::map 是不是包含键?

如何将带有对象作为键的 Ruby 哈希对象作为 Map 对象发送到前端 Javascript