17

Here is some example Javascript (ES6) code that does not do what one might intuitively imagine.

const exampleMap = new Map([[{a: 1}, 2]]);
console.log(exampleMap.get({a: 1}));

As it turns out, this prints undefined. Why? The reasoning is covered in this StackOverflow answer. Per the MDN entry for Map, Map uses === for key equality. And, per the MDN entry for ===, Objects are compared by reference equality.

That's all fine and good. It does exactly what the docs say it should. Unfortunately, what the above code is trying to do would be quite useful, even if it isn't the actual behavior per the spec.

How can I use Map, or what should I use instead of Map, to get a key-value lookup where the keys are compared by object deep-equality semantics?

2
  • "object deep-equality semantics"? You mean stringification? Then stringify it, and a simple plain Object will do. {a:1} is semantically different than {a:1} in javascript. Commented Jul 30, 2019 at 1:31
  • See also Define a custom hash() method for use with ES6 Maps Commented Jun 13, 2021 at 23:35

4 Answers 4

1

You could create your own function, where you pass through the map (m) you want to get the value of, and a key you want to search in the map. You can then stringify your key, such that you can search the keys in your map and compare them against this stringified key

const exampleMap = new Map([[{a: 1}, 2]]);

const getMapVal = (m, key) => {
  const strKey = JSON.stringify(key);
  return m.get(Array.from(m.keys()).find((k) => JSON.stringify(k) === strKey));
}

console.log(getMapVal(exampleMap, {a: 1})); // 2 (gives undefined if key doesn't exists)

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

2 Comments

Seem to me it's simpler to set map with singified keys already: map.set(JSON.stringify(key), value); const value2 = exampleMap.get(JSON.stringify(key)).
@xmedeko Yes I would say that's easier, think I was trying to follow the OPs code where they originally use an object as a key and then want to try and get the value back using the same object shape. I'm hoping for this proposal to land soon, it'd make this sort of thing so much nicer: github.com/tc39/proposal-record-tuple
0

Here's something that does a deep equality check. It relies on JSON.stringify though so it might be a performance issue for very large object keys. This also updates the Map prototype for use in the same way as .get.

Object.defineProperty(Map.prototype, 'deepCheck', {
  value: function(lookupKey) {
    let lookupValue;
    const lookupKeyStr = JSON.stringify(lookupKey);
    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    const iterator = this.entries();
    let result = null;


    while (true) {
      result = iterator.next();
      if (result.done) {
        break;
      }
      if (JSON.stringify(result.value[0]) === lookupKeyStr) {
        lookupValue = result.value[1];
      }
    }

    return lookupValue;
  }
});

const exampleMap = new Map([[{a: 1}, 2]]);

console.log(exampleMap.deepCheck({a: 1}));

Comments

0

Very late to the party, but this library does exactly what you're looking for: https://github.com/adamhamlin/deep-equality-data-structures

const map = new DeepMap([[{a: 1}, 2]]);
console.log(map.get({a: 1})); // Prints: 2

Full disclosure: I am the library author

Comments

-1

You need to somehow compare against or get a reference to the exact object that was used as the Map key. One option would be to iterate over the Map's entries, and check for one whose key has an a value of 1:

const exampleMap = new Map([[{a: 1}, 2]]);
const foundEntry = [...exampleMap.entries()]
  .find(([key, val]) => key.a === 1);
  
console.log(
  foundEntry
  ? foundEntry[1]
  : 'Not found!'
);

Another approach:

const exampleMap = new Map([[{a: 1}, 2]]);
const foundKey = [...exampleMap.keys()]
  .find(key => key.a === 1);
  
console.log(
  foundKey
  ? exampleMap.get(foundKey)
  : 'Not found!'
);

Comments

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.