Objects are pretty cool I guess

But we can do better!

Map

A collection of keyed data items. Keys can be any type.

new Map()           // creates the map
map.set(key, value) // stores the value against the key
map.get(key)        // returns the value associated with the key
map.has(key)        // true if the key exists, otherwise false
map.delete(key)     // removes the value by the key
map.clear()         // clears the map
map.size            // returns the current element count   

Keys are compared using ===, except NaN will equal NaN.

const map = new Map();

map.set('123', 'string keys are cool');
map.set(123, 'number keys are cooler');
map.set(true, 'too true!');

// A regular Object would convert keys to strings,
// so these two would not be different:

console.log(map.get('123'));    // 'string keys are cool'
console.log(map.get(123));      // 'number keys are cooler'

console.log(map.size);          // 3

Map example one

const ariela = {name: 'Ariela'};
const takayoshi = {name: 'Takayoshi'};

const ages = new Map();

// Note that map methods return themselves, so you can chain
ages.set(ariela, 53) 
    .set(takayoshi, 30);

console.log(ages.get(ariela)); // 53

Map example two

const map = new Map([
  ['name', 'Takayoshi'],
  ['age', 30]
]);

const map = new Map(Object.entries({
  name: 'Takayoshi',
  age: 30
}));

Map from Object

const menu = new Map([
  ['avo poached eggs', 13],
  ['grilled grapefruit', 6],
  ['coconut chia pot', 7]
]);

for (let menuItem of menu.keys()) {
  console.log(menuItem);    // avo poached eggs, grilled...
}

for (let amount of menu.values()) {
  console.log(amount);     // 13, 6, 7
}

for (let entry of menu) { // Same as of menu.entries()
  console.log(entry);     // avo poached eggs,13...
}

menu.forEach((value, key, map) => {
  console.log(`${key}: ${value}`); // avo poached eggs: 13 etc
});

Map iteration

Iteration order is  retained 🎉

Set

A collection of values where each value may occur only once.

new Set(iterable)       // creates the set
set.add(value)          // adds a value
set.delete(value)       // removes value, returns true if value existed
set.has(value)          // returns true if the value exists in the set
set.clear()             // removes everything from the set
set.size                // returns the current element count
const visits = new Set();

const ariela = {name: 'Ariela'};
const takayoshi = {name: 'Takayoshi'};
const lana = {name: 'Lana'};

// Visits, some users come multiple times
visits.add(ariela);
visits.add(takayoshi);
visits.add(lana);
visits.add(ariela);
visits.add(lana);

console.log(visits.size); // 3 - only unique values

for (let user of visits) {
  console.log(user.name); // In order: Ariela, Takayoshi, Lana
}

Set example

const morningTea = new Set(['croissant', 'macaron', 'financier']);

for (let value of morningTea) {
    console.log(value);
}

// Note the weirdness here
morningTea.forEach((value, valueAgain, morningTea) => {
    console.log(value);
});

// Both print croissant, macaron, financier

Set iteration

GC refresher

  • Memory management in JavaScript is performed automatically and invisibly to us
  • Anything no longer "reachable" is cleaned up
  • "Reachable" values are those that are accessible or usable somehow
let ariela = {name: 'Ariela'};

// The object can be accessed, ariela is the reference to it

// Let's overwrite the reference..
ariela = null;

// The object will be removed from memory

GC example

GC continued

  • Usually, properties of an object or elements of an array or another data structure are considered reachable while that data structure is in memory
  • If we use an object in a Map, it's kept in memory even if there are no more references to it.
let takayoshi = {name: 'Takayoshi'};

const secrets = new Map();
secrets.set(takayoshi, 'Likes The Good Place');

takayoshi = null; // Overwrite the reference

// takayoshi is stored inside the map - we can
// still get it using secrets.keys()

WeakMap

A Map that does not prevent object removal from memory.

let lana = {name: 'Lana'};

const weakAgeMap = new WeakMap();

// Keys must be Objects
weakAgeMap.set(lana, 8);

lana = null; // Overwrite the reference

// There are no references except WeakMap, so the Lana object is
// removed both from the memory and from weakAgeMap automatically

WeakMap does not support methods keys(), values(), entries(), we can not iterate over it.

weakMap.get(key)
weakMap.set(key, value)
weakMap.delete(key, value)
weakMap.has(key)

WeakMap methods

WeakSet

A Set (of objects) that only exist while they are reachable elsewhere.

Like Set, it supports add, has and delete, but not size or keys(). You can't iterate over a WeakSet.

WeakSet example

const messages = [
    {text: 'How do you like your eggs?', from: 'Takayoshi'},
    {text: 'Scrambled', from: 'Ariela'},
    {text: 'Let\'s do brunch!', from: 'Lana'}
];

// Fill it with array elements (3 items)
const unreadSet = new WeakSet(messages);

// We can use unreadSet to see whether a message is unread
console.log(unreadSet.has(messages[1])); // true

// Remove it from the set after reading
unreadSet.delete(messages[1]); // true

// If we remove an item from our message list, the set is
// cleaned up automatically
messages.shift();

// No need to clean unreadSet, it now has 2 items
// unfortunately, there's no method to get the exact count
// of items, so can't show it

WeakMap & WeakSet

The absence of iterations and inability to get all the current content seem inconvenient, but their main job is to be additional storage of data for objects which are stored / managed elsewhere.

Map and Set

By Helen Durrant

Map and Set

Let's talk about Map and Set

  • 328