What Is the Difference Between Set, Map, WeakSet, and WeakMap in JavaScript?
February 13, 2023
Set
Set is a data structure similar to an array, but withuniqueelement values, meaning that there are no duplicate values, whether they are primitive values or object references. In JavaScript, Set is a constructor function used to generate an instance of the Set data structure. The way to create an instance is to use new Set()
.
The common operations of Set include:
add(value)
: Used to add values.delete(value)
: Used to delete values in a Set.has(value)
: Used to determine if a value exists in a Set.size
: Used to obtain the number of elements.
Set does not have a key, and if you use entries()
to traverse the Set, the returned elements will be in the form of [value, value]
.
const set1 = new Set();
set1.add(42);
set1.add("forty two");
const iterator1 = set1.entries();
for (const entry of iterator1) {
console.log(entry);
// expected output: [42, 42]
// expected output: ["forty two", "forty two"]
}
The Difference Between Set and WeakSet
The methods and usage of WeakSet are similar to those of the Set data structure, and this section will focus on the differences between the two.
The element values in WeakSet can only be non-null objects, while Set can accept values of various data types.
const wSet = new WeakSet(); const a = [1, 2, 3]; const b = { name: "explainthis" }; wSet.add(a); // WeakSet {Array(3)} wSet.add(b); // WeakSet {{...}} wSet.add(1); // Uncaught TypeError: Invalid value used in weak set
The elements in WeakSet are all "weak references" and can be garbage collected. Even if a value stored in Set is no longer referenced in other parts of the program, it will still exist in Set and will not be garbage collected. However, if it is a WeakSet, it will be garbage collected. If you want to manage memory more precisely, WeakSet can be very useful in many cases.
const disableElements = new WeakSet(); const loginButton = document.querySelector("#login"); // By checking whether an element is in the set, // we can know whether it is disabled or not. // Once an element is removed from the DOM tree, // WeakMap will release its memory // (assuming that there is no other reference to this object). disableElements.has(loginButton); // true
Map
Map Map is a data structure similar to Object, which stores data in the form of key-value pairs. However, there are many differences between them. For details, please refer to the article What is the Difference Between Map and Object in JavaScript, and Why Do We Need Map?
Map itself is a constructor function used to create Map data structures, and the way to do it is to use new Map()
to create an instance.
Common methods of Map:
set(key, value)
: add a key-value pair to Map.get(key)
: get a specific value through its key.has(key)
: check whether a certain key exists in Map.delete(key)
: remove a specific element from Map through its key.size
: get the number of elements in Map.
Common traversal methods of Map (the traversal order is the insertion order):
values()
: return all values in Map.keys()
: same as values().entries()
: return all elements
The Difference Between Map and WeakMap
The methods and usage of WeakMap are similar to those of Map data structure, and this section will focus on the differences between the two.
WeakMap only allows objects as key names, except for null. Map can accept various data types as key names.
The key names in WeakMap are "weak references", and the objects to which the key names (keys) point can be garbage collected.
// If the object inserted has no other reference outside, it will be garbage collected in WeakMap
let food = new WeakMap();
let fruit = { name: "apple" };
food.set(fruit, "good"); // put the fruit object into WeakMap
fruit = null; // remove the reference of fruit
console.log(food);
// Due to the differences in garbage collection timing across different JavaScript engines, the object might not be immediately garbage collected. Therefore, the following two scenarios might be logged:
// WeakMap {Object => "good"}, the reference to 'fruit' has been removed, but the object might not have been garbage collected yet.
// WeakMap(0), 'fruit' has been garbage collected, so there are no entries in the WeakMap.
// For the common Map, even if the object inserted has no other reference outside, it still exists in Map.
let food = new Map();
let fruit = { name: "apple" };
food.set(fruit, "good");
console.log(food); // Map(1)
fruit = null;
console.log(food); // Map(1), fruit will not be garbage collected
In the strong reference code above, although the fruit
object is reassigned to null
(which means that the value of this object cannot be obtained through the fruit
variable, because the reference has been disconnected), it is retained in memory because of the strong reference between food
and this object. This is what was mentioned earlier: strong references prevent objects from being garbage collected and keep them in memory; weak references are the opposite and cannot prevent objects from being garbage collected. When the JavaScript execution environment executes garbage collection, the fruit
object in the weak reference example above will be removed from memory if we use a WeakMap.
The appropriate situation to use weak references is when the referenced object may be deleted in the future and you want it to be garbage collected. For example, if we want to record some data related to DOM nodes, one way is to use Expando to extend the information on nodes, but the disadvantage is that it will directly modify the DOM node, and if the node is removed in the future, the related information will not be garbage collected. To address this, using WeakMap will be a good alternative solution.