23

Looking at a couple of different docs, all I see is when the Map (ECMAScript 6) key is a boolean, string, or integer. Is there a way we could use another customized Object (called with the new CustomObject(x,y) constructor call) to be added as a key?

I am able to add an object as a key, but unable to check if the Map has the said object:

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


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

Is there a way around this?

  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
}
3
  • 1
    Yes, you can use any object as a key. It has to be the same object each time, though – not just an object with the same keys and values. A nested Map is one option to implement Tuple lookup. Commented Jul 6, 2017 at 18:57
  • 1
    unfortunately I cannot check if it's the same object itself. It has to be an object with some common properties that are set the same. Is there any way to do this? Commented Jul 7, 2017 at 1:19
  • 1
    As a Java programmer, these semantics of the Javascript Map are surprising and confusing. In Java, we must provide equals() and hashCode() methods for our classes, and the Java HashMap class then works as expected when using keys that are different objects but are equivalent objects (that is, keys can have value semantics). Commented Dec 15, 2020 at 12:09

2 Answers 2

23

You just have to save the reference to the object:

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'

Edit: Here is how to use an object to achieve what you want, which is to compare objects by their values rather than by reference:

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'

These operations will run in constant time on average, which is much faster than searching through a Map for a similar object key in linear time.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. unfortunately, I cannot use the same myKey reference to the object. I am checking for an object with the same set of properties. Is there any way to get around this.
@LoserCoder Yes, create a toString() method for your class that generates the same strings for instances with the same values, and then just use those strings as keys in an object (that way you don't even have to use Map). This is simply how Maps and object comparisons work in JS - objects are compared by reference.
@LoserCoder I added an example of what I mean. This approach leaves it up to you to ensure that your toString methods are able to accurately serialize your value objects for comparison. Just because two object are created with the same constructor and arguments doesn't mean they are necessarily equivalent.
4

When you set an object to the map, you need to pass the same memory reference when checking if the map has it.

Example:

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.

EDIT

If you really have to do this, you could do the following:

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

3 Comments

True, but I am looking for if there is a known workaround. Or should I not use Set/Map in this scenario at all. If so, I may have to use object references directly, but that will cause the same issue.
Edited my answer with a possible workaround. @LoserCoder
Note that this approach uses a linear lookup that will run significantly slower than using the JavaScript engine's built in object key resolution algorithm (hash tables), which is constant time on average.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.