Map, WeakMap, Set, and WeakSet in JavaScript

Map, WeakMap, Set, and WeakSet in JavaScript

  • 66

Map, WeakMap, Set, and WeakSet in JavaScript .Still, many teams or companies don’t use Maps or Sets, I think. Maybe it’s because they don’t feel it’s necessary or because arrays still can do almost everything they want.

I’d guess that over 70% of JavaScript developers have only used objects for the collecting and maintaining the data in their projects. Well, it’s actually so true that the newer collection objects, such as Map and Set, are way underused, even though they came out in 2015.

So today, I’m going to talk about the fantastic new features from 2015 — Map, Set, WeakMap, and WeakSet.

Prior to reading

  • This article isn’t going to tell you only to use them. But I’ve seen some applicants who used one of them in the coding test, and I liked the use of them in certain situations. It’s up to you to decide when to use them in your project.
  • You should know what iterables are in order to understand what I’ll be talking about better. Check out my previous article for more about them.

Objects

We should talk about how to use objects first.

Well, I’m sure over 90% of you already know this part since you clicked this article in order to get to know the new collection objects, but for beginners of JavaScript, let’s briefly talk about them.

const algorithm = { site: "leetcode" };
console.log(algorithm.site); // leetcode
for (const key in algorithm) {
  console.log(key, algorithm[key]);
}
// site leetcode
delete algorithm.site;
console.log(algorithm.site); // undefined

So I made an algorithm object whose key and value are a string-type value. And I’ve checked the value successfully by approaching it with the . keyword.

Also, a for-in loop is good for looping through the object. You can access the value corresponding to its key with the [] keyword. But a for-of loop can’t be used because objects aren’t iterable.

The property of objects can be removed with the delete keyword. This completely gets rid of the property from the object, and you should be careful not to be confused with this approach.

const algorithm = { site: "leetcode" };
// Property is not removed!!
algorithm.site = undefined;
// Property is removed!!
delete algorithm.site;

algorithm.site = undefined just assigns the new value to site .

OK, we’ve quickly discussed a few things about objects:

  • How to add properties
  • How to loop over the object
  • How to remove properties

Map

A Map is a new collection object in JavaScript that functions like an object. But there are a few primary differences compared to a regular object.

Firstly, let’s take a look at a simple example creating a Map object.

How to add properties

const map = new Map();
// Map(0) {}

That’s it. Map doesn’t require anything to be created. But the way you can add data is slightly different.

map.set('name', 'john');
// Map(1) {"name" => "john"}

Map has a special method for adding a property in it called set. It takes two arguments: the key as the first argument and the value as the second.

map.set('phone', 'iPhone');
// Map(2) {"name" => "john", "phone" => "iPhone"}
map.set('phone', 'iPhone');
// Map(2) {"name" => "john", "phone" => "iPhone"}

However, it doesn’t allow you to add the existing data in it. If the value corresponding to the key of the new data has already existed in the Map object, the new data won’t be added.

map.set('phone', 'Galaxy');
// Map(2) {"name" => "john", "phone" => "Galaxy"}

But you can overwrite the existing data with a different value.

How to loop over the object

Map is an iterable object, which means it can be mapped over with a for-of statement.

for (const item of map) {
  console.dir(item);
}
// Array(2) ["name", "john"]
// Array(2) ["phone", "Galaxy"]

One thing to remember is Map gives you data as an array form. You should destructure the array or access each index to get the key or the value.

To get the keys or the values only, there are methods for you to follow as well.

map.keys();
// MapIterator {"name", "phone"}
map.values();
// MapIterator {"john", "Galaxy"}
map.entries();
// MapIterator {"name" => "john", "phone" => "Galaxy"}

You can even use the spread operator to get the full data of Map because the spread operator also works with iterable objects behind the scene.

const simpleSpreadedMap = [...map];
// [Array(2), Array(2)]

How to remove properties

It’s also very easy to remove data from the Map object. All you need to do is call delete.

map.delete('phone');
// true
map.delete('fake');
// false

The delete returns the boolean, which indicates whether or not the deleting function successfully deleted the data. If yes, it returns true, and otherwise, it returns false.

WeakMap

WeakMap originated from Map, so they are very similar to each other. However, WeakMap has one big difference.

How does WeakMap get its name? Well, it’s because its connection or relation to the data object its reference link refers to isn’t as strong as Map’s connection or relation, making it weak.

So what does this exactly mean?

Difference 1: The key must be an object

const John = { name: 'John' };
const weakMap = new WeakMap();
weakMap.set(John, 'student');
// WeakMap {{...} => "student"}
weakMap.set('john', 'student');
// Uncaught TypeError: Invalid value used as weak map key

You could pass any value as the key into the Map object, but WeakMap is different. It only accepts an object as the key; otherwise, it returns an error.

Difference 2: Not all methods from Map are supportive

The methods you can use with WeakMap are as follows.

  • delete
  • get
  • has
  • set

The big difference in this topic is that WeakMap doesn’t support the methods for iterating the object. But why? It’s described down below.

Difference 3: Data is removed when GC cleans up the reference

This is the biggest difference compared to Map.

let John = { major: "math" };
const map = new Map();
const weakMap = new WeakMap();
map.set(John, 'John');
weakMap.set(John, 'John');
John = null;
/* John is garbage-collected */

When the John object is garbage-collected, the Map object keeps holding the reference link, while the WeakMap object loses the link. So when you use WeakMap, you should consider this feature.

Set

Set is also quite similar to Map, but Set is more useful for a single value.

How to add properties

const set = new Set();
set.add(1);
set.add('john');
set.add(BigInt(10));
// Set(4) {1, "john", 10n}

Like Map, Set also prevents us from adding the same value.

set.add(5);
// Set(1) {5}
set.add(5);
// Set(1) {5}

How to loop over the object

Since Set is an iterable object, you can use a for-of or forEach statement.

for (const val of set) {
  console.dir(val);
}
// 1
// 'John'
// 10n
// 5
set.forEach(val => console.dir(val));
// 1
// 'John'
// 10n
// 5

How to remove properties

This part is exactly the same as Map’s deletion. It returns true if the data is successfully removed; otherwise, it returns false.

set.delete(5); 
// true
set.delete(function(){});
// false;

Set could be quite useful when you don’t want to add the same values into the array form.

/* With Set */
const set = new Set();
set.add(1);
set.add(2);
set.add(2);
set.add(3);
set.add(3);
// Set {1, 2, 3}
// Converting to Array
const arr = [ ...set ];
// [1, 2, 3]
Object.prototype.toString.call(arr);
// [object Array]
/* Without Set */
const hasSameVal = val => ar.some(v === val);
const ar = [];
if (!hasSameVal(1)) ar.push(1);
if (!hasSameVal(2)) ar.push(2);
if (!hasSameVal(3)) ar.push(3);

WeakSet

Like WeakMap, WeakSet also loses the access link to inner data if they’re garbage-collected.

let John = { major: "math" };
const set = new Set();
const weakSet = new WeakSet();
set.add(John);
// Set {{...}}
weakSet.add(John);
// WeakSet {{...}}
John = null;
/* John is garbage-collected */

Once the object,John is garbage-collected, WeakSet has no way to access its data that was referencing John. And WeakSet doesn’t support for-of or forEach since it’s not iterable.

Summary of Comparison

All

  • Adding the same value isn’t supportive

Map vs. WeakMap

  • WeakMap only accepts the object as the key, while Map doesn’t

Map and Set

  • Iterable object — for-of, forEach, or spread operator is supported
  • Free from GC relation

WeakMap and WeakSet

  • Not an iterable object — can’t loop over
  • Can’t access the data if the referencing data is garbage-collected
  • Less supportive methods

Conclusion

Still, many teams or companies don’t use Maps or Sets, I think. Maybe it’s because they don’t feel it’s necessary or because arrays still can do almost everything they want.

However, Maps or Sets could be very unique and powerful things in JavaScript, depending on each situation. So I hope one day, you could have a chance to use them.