Built-in objects: Set and Map

Sets and maps are recent additions to JavaScript and they’re quite powerful data structures, which we can use along with arrays.

JavaScript Sets

A Set data structure allows to add data to a container.

A Set is a collection of objects or primitive types (strings, numbers or booleans), and you can think of it as a Map where values are used as map keys, with the map value always being a boolean true.

Initialize a Set

A Set is initialized by calling:

const s = new Set()

Add items to a Set

You can add items to the Set by using the add method:

s.add('one')
s.add('two')

A set only stores unique elements, so calling s.add('one') multiple times won’t add new items.

You can’t add multiple elements to a set at the same time. You need to call add() multiple times.

Check if an item is in the set

Once an element is in the set, we can check if the set contains it:

s.has('one') //true
s.has('three') //false

Delete an item from a Set by key

Use the delete() method:

s.delete('one')

Determine the number of items in a Set

Use the size property:

s.size

Delete all items from a Set

Use the clear() method:

s.clear()

Iterate the items in a Set

Use the keys() or values() methods - they are equivalent:

for (const k of s.keys()) {
  console.log(k)
}

for (const k of s.values()) {
  console.log(k)
}

The entries() method returns an iterator, which you can use like this:

const i = s.entries()
console.log(i.next())

calling i.next() will return each element as a { value, done = false } object until the iterator ends, at which point done is true.

You can also use the forEach() method on the set:

s.forEach(v => console.log(v))

or you can just use the set in a for..of loop:

for (const k of s) {
  console.log(k)
}

Initialize a Set with values

You can initialize a Set with a set of values:

const s = new Set([1, 2, 3, 4])

Convert to array

Convert the Set keys into an array

const a = [...s.keys()]

// or

const a = [...s.values()]

A WeakSet

A WeakSet is a special kind of Set.

In a Set, items are never garbage collected. A WeakSet instead lets all its items be freely garbage collected. Every key of a WeakSet is an object. When the reference to this object is lost, the value can be garbage collected.

Here are the main differences:

  1. you cannot iterate over the WeakSet
  2. you cannot clear all items from a WeakSet
  3. you cannot check its size

A WeakSet is generally used by framework-level code, and only exposes these methods:

  • add()
  • has()
  • delete()

JavaScript Maps

What is a Map

A Map data structure allows to associate data to a key.

Before ES6

ECMAScript 6 (also called ES2015) introduced the Map data structure to the JavaScript world, along with Set.

Before its introduction, people generally used objects as maps, by associating some object or value to a specific key value:

const car = {}
car['color'] = 'red'
car.owner = 'Flavio'
console.log(car['color']) //red
console.log(car.color) //red
console.log(car.owner) //Flavio
console.log(car['owner']) //Flavio

Enter Map

ES6 introduced the Map data structure, providing us a proper tool to handle this kind of data organization.

A Map is initialized by calling:

const m = new Map()

Add items to a Map

You can add items to the map by using the set method:

m.set('color', 'red')
m.set('age', 2)

Get an item from a map by key

And you can get items out of a map by using get:

const color = m.get('color')
const age = m.get('age')

Delete an item from a map by key

Use the delete() method:

m.delete('color')

Delete all items from a map

Use the clear() method:

m.clear()

Check if a map contains an item by key

Use the has() method:

const hasColor = m.has('color')

Find the number of items in a map

Use the size property:

const size = m.size

Initialize a map with values

You can initialize a map with a set of values:

const m = new Map([['color', 'red'], ['owner', 'Flavio'], ['age', 2]])

Map keys

Just like any value (object, array, string, number) can be used as the value of the key-value entry of a map item, any value can be used as the key, even objects.

If you try to get a non-existing key using get() out of a map, it will return undefined.

Weird situations you’ll almost never find in real life

const m = new Map()
m.set(NaN, 'test')
m.get(NaN) //test
const m = new Map()
m.set(+0, 'test')
m.get(-0) //test

Iterating over a map

Iterate over map keys

Map offers the keys() method we can use to iterate on all the keys:

for (const k of m.keys()) {
  console.log(k)
}

Iterate over map values

The Map object offers the values() method we can use to iterate on all the values:

for (const v of m.values()) {
  console.log(v)
}

Iterate over map key, value pairs

The Map object offers the entries() method we can use to iterate on all the values:

for (const [k, v] of m.entries()) {
  console.log(k, v)
}

which can be simplified to

for (const [k, v] of m) {
  console.log(k, v)
}

Convert to array

Convert the map keys into an array

const a = [...m.keys()]

Convert the map values into an array

const a = [...m.values()]

WeakMap

A WeakMap is a special kind of map.

In a map object, items are never garbage collected. A WeakMap instead lets all its items be freely garbage collected. Every key of a WeakMap is an object. When the reference to this object is lost, the value can be garbage collected.

Here are the main differences:

  1. you cannot iterate over the keys or values (or key-values) of a WeakMap
  2. you cannot clear all items from a WeakMap
  3. you cannot check its size

A WeakMap exposes those methods, which are equivalent to the Map ones:

  • get(k)
  • set(k, v)
  • has(k)
  • delete(k)

The use cases of a WeakMap are less evident than the ones of a Map, and you might never find the need for them, but essentially it can be used to build a memory-sensitive cache that is not going to interfere with garbage collection, or for careful encapsualtion and information hiding.

Lessons in this unit:

0: Introduction
1: The global object
2: Object properties
3: Number
4: String
5: Math
6: JSON
7: Date
8: Intl
9: ▶︎ Set and Map
Are you intimidated by Git? Can’t figure out merge vs rebase? Are you afraid of screwing up something any time you have to do something in Git? Do you rely on ChatGPT or random people’s answer on StackOverflow to fix your problems? Your coworkers are tired of explaining Git to you all the time? Git is something we all need to use, but few of us really master it. I created this course to improve your Git (and GitHub) knowledge at a radical level. Launching May 21, 2024. Join the waiting list!