Creating Maps with unique object keys in JavaScript
Often there are requirements where we need to create a Map which uniquely identifies buckets based on a key value. We already have this structure in almost any language we can think of. For example, Java has the well known HashMap, which stores data in buckets, and each bucket is located by the value of its key.
Maps in JavaScript are a bit different. Although they were created to make it convenient for us to store objects as keys, there is a problem. Consider there are two objects having the exact same properties.
let object1 = {
name: "abc",
age: 25
}
let object2 = {
name: "abc",
age: 25
}
Now we can think of adding these objects as a key to the Map, like below
let ourMap = new Map();
ourMap.set(object1, "some value");
ourMap.set(object2, "this value should be updated");
In the resulting Map, we will have two different keys created.
This is a problem if we want the Map to consider keys having objects with the same values as equal.
Solution: use Symbols
Symbol is a recent primitive data type added in JavaScript. Note that Symbol data type is not of object type, but a primitive one.
We create Symbols like below
let sym = Symbol();
let symWithDescription = Symbol("this is a description");
Note that there is no new keyword being used, as in the case of objects.
Symbols have a special key associated with each one of them. We can create a Symbol for a specific key using its method for()
let symFor123 = Symbol.for(123);
JavaScript first checks if a Symbol for key 123 is already created, and only if there is no such Symbol created, it creates a new one.
Note that Symbol(123) is not the same as Symbol.for(123).
The constructor parameter is only a description of the symbol in case of Symbol(123) whereas in case of Symbol.for(123) we are creating a Symbol for key 123
console.log(Symbol(123) == Symbol.for(123)); //false
console.log(Symbol(123) === Symbol.for(123)); //false
Now we have a solution to have unique keys in our Map based on object properties. We just have to create Symbols for objects!
let object1 = {
name: "abc",
age: 25
}
let object2 = {
name: "abc",
age: 25
}
console.log(Symbol.for(object1) == Symbol.for(object2)); //true
JavaScript will consider Symbol to be already created for object having same properties key-value pairs. So a new Symbol will not be created when we execute Symbol.for(object2)
Using the above concept in our Map
let object1 = {
name: "abc",
age: 25
}
let object2 = {
name: "abc",
age: 25
}
let ourMap = new Map();
ourMap.set(Symbol.for(object1), "some value");
ourMap.set(Symbol.for(object2), "this value should be updated");
Now our Map will have only one key-value pair at the end. As we are using Symbol as our key for the Map, the second set operation will just update the value for that key.
Read more about Symbols here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
Do let me know if you have any feedback.
Thank you!