Overview
Before ES6 in order to store the key value
pair we had to use objects. We never had any extra data structure except for an array.
With the introduction of javascript Map and Set, we have something extra to handle the data.
Maps
Just like Sets, Maps are also used to store the unique values except here it is key value
pair.
Before ES6
Prior to the introduction of javascript Map developers used to have a workaround to handle the key value
pair but there was limitations to that workaround. Let us see the workaround first to see why there was need for the Maps.
var map = {}; map.foo = "bar"; // retrieving a value let value = map.foo; console.log(value);
This approach works fine but if the situation gets more complex when we run into the limitations of the object properties.
var map = {}; map[5] = "bar"; console.log(map["5"]);
Object internally converts anything to string
to store the values. So the numeric 5
is converted to "5"
. Thus we cannot use numeric key.
The same happens when we use objects
as the key.
var map = {}; var key = {}; var key2 = {}; map[key] = 'prashant'; console.log(map[key2]); //prashant
It converts the object
to string
.
Maps with falsy key were also difficult to handle.
var map = {}; map.foo = false; // checking for the existence of "foo" or a nonzero value? if (map.foo) { // ... }
Here we want to check if value is present inside the key foo
but the falsy value is automatically converted to the false.
After ES6
Maps are ordered list of key value
pair where key
as well as value
can be of any type.
Syntax
let map = new Map([iterable]);
If an Iterable object like Array(arrays with two elements, e.g. [[ 1, ‘one’ ],[ 2, ‘two’ ]]) whose elements are key-value pairs is passed then all its items will be added to the Map.
null
values are treated as undefined
.
let map = new Map(); map.set(5, 'prashant'); map.set('5', 'yadav'); console.log(map.size); // 2 console.log(map.get(5)); // 'prashant' console.log(map.get('5')); // 'yadav' let map2 = new Map([["name", "prashant"], ["age", 23]]); console.log(map2.size); // 2 console.log(map2.get('name')); // prashant
we can also use objects
as the key.
let map = new Map(); let key1 = {}; let key2 = {}; map.set(key1, 'prashant'); map.set(key2, 'yadav'); console.log(map.size); // 2 console.log(map.get(key1)); // 'prashant' console.log(map.get(key2)); // 'yadav'
Map Properties
- Map.prototype.constructor: Returns the function that created an instance’s prototype.
- Map.prototype.size: Returns the size of the map.
Map Methods
- Map.prototype.set(key, value): Add the
value
for thekey
and returns the Map object. - Map.prototype.clear(): Removes all the items.
- Map.prototype.delete(key): Removes particular items with the given
key
. - Map.prototype.enteries(): Returns an Iterator object that contains an array of
key value
in the way they were added. - Map.prototype.foreach(callback, thisArg): Calls the callback function once for each of the items in their insertion order. If thisArgs is passed then it will be called like
this
for each callback. - Map.prototype.has(key): Returns
true
if item with givenkey
is present,false
otherwise. - Map.prototype.get(key): Returns value of the item with given
key
,undefined
otherwise. - Map.prototype[@@iterator](): Returns a new Iterator object that contains the array of
key value
for each element in the Map. - Map.prototype.keys(): Returns a new Iterator object that contains the
keys
for each element in the Map. - Map.prototype.values(): Returns a new Iterator object that contains the
values
for each element in the Map.
Adding item to the javascript map
let map = new Map(); map.set(1, 'prashant'); map.set(2, 'anil'); map.set(3, 'taha'); map.set(4, 'ankit'); map.set(4, 'ankit'); //ignores the duplicate values map.set('4', 'yadav'); map.set('fullname', 'My name is Prashant Yadav'); map.set(undefined, 20); let key = {a: 0, b: 1}; map.set(key, 25); let key2 = function() {}; map.set(key2, 27); map.set(null, 23); console.log(map.size); // 9 console.log(map); /* Map(9) {1 => "prashant", 2 => "anil", 3 => "taha", 4 => "ankit", "4" => "yadav", …} size: (...) __proto__: Map [[Entries]]: Array(9) 0: {1 => "prashant"} 1: {2 => "anil"} 2: {3 => "taha"} 3: {4 => "ankit"} 4: {"4" => "yadav"} 5: {"fullname" => "My name is Prashant Yadav"} 6: {undefined => 20} 7: {Object => 25} 8: {null => 23} length: 9 */
Finding item in Map
console.log(map.has(key)); // true console.log(map.has(null)); // true console.log(map.has(key2)); // true console.log(map.has(0)); // false
Always pass objects
as keys
by storing it in variables let key = {a: 0, b: 1};
Getting the value
of a given key
console.log(map.get(key)); // 25 console.log(map.get(null)); // 23 console.log(map.get(0)); // undefined
Removing an item with the given key
from the Map
map.delete(key); map.delete(null); console.log(map.has(key)); // false console.log(map.has(null)); // false
Iterating with maps
Simple Iterations
map.forEach((value, key, ownerMap) => { console.log(key + " " + value); console.log(ownerMap === map); }); /* 1 prashant true 2 anil true 3 taha true 4 ankit true 4 yadav true fullname My name is Prashant Yadav true undefined 20 true [object Object] 25 rue null 23 true */
We have used =>
arrow function, ownerMap
is passed as this
which equals to the current object ownerMap === map
that is why it is returning true
.
Using for of loop.
for(const [key,val] of map){ console.log(key,val); } /* 1 "prashant" 2 "anil" 3 "taha" 4 "ankit" 4 yadav fullname My name is Prashant Yadav undefined 20 {a: 0, b: 1} 25 ƒ () {} 27 null 23 */
Using Map.prototype.keys()
.
for (var key of map.keys()) { console.log(key); } /* 1 2 3 4 '4' fullname undefined {a: 0, b: 1} ƒ () {} null */
Using Map.prototype.values()
.
for (var key of map.values()) { console.log(key); } /* prashant anil taha ankit yadav My name is Prashant Yadav 20 25 27 23 */
Using Map.prototype.entries()
.
We can destructure the value to access them separately.
for (let [key, value] of map.entries()) { console.log(key + ' = ' + value); } /* 1 = prashant 2 = anil 3 = taha 4 = ankit 4 = yadav fullname = My name is Prashant Yadav undefined = 20 [object Object] = 25 function() {} = 27 null = 23 */
WeakMaps
WeakMaps are to the Maps what WeakSets are to the Sets. In weakMap every key
must be object, inserting an non-object will result in error. Objects are held weakly so that if there is no reference to key
then that key value
will be removed from the WeakMap or garbage collected.
Syntax
let key1 = {}, key2 = {}; let weakMap = new WeakMap([[key1, "prashant"], [key2, 23]]); console.log(weakMap.has(key1)); // true console.log(weakMap.get(key1)); // "prashant" console.log(weakMap.has(key2)); // true console.log(weakMap.get(key2)); // 23
The WeakMap cleans itself once the key
is deleted or if there is no reference to the key
.
let dad = { name: "Daddy" }; let mom = { name: "Mommy" }; const map = new Map(); const weakMap = new WeakMap(); map.set(dad, 1); weakMap.set(mom, 2); dad = null; mom = null; map; // Map(1) {{…}} weakMap; //Wait for few seconds // WeakMap {}
As we can see we mom
was garbage collected when we set its value to null
while dad
is still present.
Difference between Maps and WeakMaps
- WeakSets can use objects as
key
unlike the Maps. - Passing non-objects as
key
will result in error. - The
has(key)
anddelete(key)
method returns false for non-object. - They have only four methods
has(key), delete(key), get(key), set(key, value)
. - WeakMaps are not Iteratable.
WeakMaps are very useful when creating objects related to particular DOM elements. That way when DOM element is no longer associated then it will automatically be garbage collected.