# Blog

## Sets and Maps from Four Semesters of Computer Science in 5 Hours by Brian HoltPosted on August 24, 2020 in Algorithms, JavaScript by Matt Jennings

### Set

`Set` objects are collections of values. Sets are reference data types, like Arrays, and allow unique lists (ONLY unique values unliked Arrays). Sets are also iterable like Arrays.

Sets can’t be accessed like Arrays (like `arr[0] = 0;`) and don’t have indices.

Example:

```let myArray = [11, 22, 34, 65, 34];
let mySet = new Set(myArray);

console.log(mySet)
// Set {11, 22, 34, 65}

console.log(mySet);
// Set {11, 22, 34, 65, '100'}

mySet.delete(22);

console.log(mySet);
// Set {11, 34, 65, '100'}

console.log(mySet.size);
// 4

// Loop through a set using forEach
mySet.forEach(val => {
console.log(val);
});

// Loop through a set using for of
for(let val of mySet) {
console.log(val);
}

console.log(mySet.has(11));
// true

// To create empty Set
mySet.clear();```

### WeakSet

The `WeakSet` objects are collections of objects, just like `Set` objects. Also, all objects in `WeakSet` objects must be unique. However, unlike `Set` objects, `WeakSet` objects:

1. Are collections of objects only. They can’t contain values of any type, like `Set` objects can.
2. Are weak, meaning that references to objects in a `WeakSet` are held weakly. If no other references to an object stored in a `WeakSet` exist, those objects can be garbage collected, which means they’ll be removed from memory.

Finally, `WeakSet` objects are not enumerable.

```let carWeakMap = new WeakMap();

let car1 = {
make: 'Hondo',
model: 'Civic'
};

console.log(carWeakSet);
// WeakSet {Object: {make: "Honda", model: "Civic"}}

carWeakSet.delete(car1);
// WeakSet {}

```

### Map

The `Map` object holds key-value pairs and remembers the original insertion order of the keys. Objects and primitive values may be used as either a key or a value.

Some differences between `Object` and `Map` objects are:

1. The keys of `Map` can be any value, including functions, objects, or primitives.
2. The keys in `Map` are ordered. Thus, when iterating over it, a `Map` object returns keys in order of insertion.
3. The number of items in a `Map` is easily retrieved from its `size` property.
4. A `Map` is iterable.
5. A `Map` can perform better than an `Object` in same scenarios involving frequent additions and removals of key-value pairs.

Code examples:

```let myMap = new Map()

let keyString = 'a string'
let keyObj    = {}
let keyFunc   = function() {}

// setting the values
myMap.set(keyString, "value associated with 'a string'")
myMap.set(keyObj, 'value associated with keyObj')
myMap.set(keyFunc, 'value associated with keyFunc')

myMap.size              // 3

// getting the values
myMap.get(keyString)    // "value associated with 'a string'"
myMap.get(keyObj)       // "value associated with keyObj"
myMap.get(keyFunc)      // "value associated with keyFunc"

myMap.get('a string')    // "value associated with 'a string'"
// because keyString === 'a string'
myMap.get({})            // undefined, because keyObj !== {}

let myMap = new Map()
myMap.set(0, 'zero')
myMap.set(1, 'one')

for (let [key, value] of myMap) {
console.log(key + ' = ' + value)
}
// 0 = zero
// 1 = one

for (let key of myMap.keys()) {
console.log(key)
}
// 0
// 1

for (let value of myMap.values()) {
console.log(value)
}
// zero
// one

for (let [key, value] of myMap.entries()) {
console.log(key + ' = ' + value)
}
// 0 = zero
// 1 = one
myMap.get(function() {}) // undefined, because keyFunc !== function () {}

let myMap = new Map()
myMap.set(0, 'zero')
myMap.set(1, 'one')

for (let [key, value] of myMap) {
console.log(key + ' = ' + value)
}
// 0 = zero
// 1 = one

for (let key of myMap.keys()) {
console.log(key)
}
// 0
// 1

for (let value of myMap.values()) {
console.log(value)
}
// zero
// one

for (let [key, value] of myMap.entries()) {
console.log(key + ' = ' + value)
}
// 0 = zero
// 1 = one

myMap.forEach(function(value, key) {
console.log(key + ' = ' + value)
})
// 0 = zero
// 1 = one```

### WeakMap

The `WeakMap` object is a collection of key/value pairs in which the keys are weakly referenced. The keys must be objects and the values can be arbitrary values.

Keys of WeakMaps are of the type `Object` only. Primitive data types as keys are not allowed (e.g. a `Symbol` can’t be a `WeakMap` key).

Native `WeakMap`s hold “weak” references to key objects, which means that they do not prevent garbage collection in case there would be no other reference to the key object.

Because the references are weak, `WeakMap` keys are not enumerable.

Code examples:

```const wm1 = new WeakMap(),
wm2 = new WeakMap(),
wm3 = new WeakMap();
const o1 = {},
o2 = function() {},
o3 = window;

wm1.set(o1, 37);
wm1.set(o2, 'azerty');
wm2.set(o1, o2); // a value can be anything, including an object or a function
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // keys and values can be any objects. Even WeakMaps!

wm1.get(o2); // "azerty"
wm2.get(o2); // undefined, because there is no key for o2 on wm2
wm2.get(o3); // undefined, because that is the set value

wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (even if the value itself is 'undefined')

wm3.set(o1, 37);
wm3.get(o1); // 37

wm1.has(o1); // true
wm1.delete(o1);
wm1.has(o1); // false```