Keyed collections

You can use Object literals to store key-value pairs, and Arrays to store iterable collections of values. ES6 also introduces specialized data structures to suit more granular use cases: Map for key-value pairs, and Set for individual values.

A Map is an iterable data structure that stores information as key-value pairs, similar to an Object literal. Unlike Object literals, a Map allows both values and keys to have any data type, and the order elements are added to a Map is preserved when iterating over it.

To create a Map, use the Map() constructor:

const myMap = new Map();

myMap;
> Map(0)

You can pre-populate a Map with data using a syntax that resembles an array (or any iterator object) containing array-like objects made up of two elements. The first element in each of these two-element data structures becomes the key, while the second becomes the value associated with that key. The simplest form of this is, effectively, an array in which each element is itself an array made up of two elements, the key and the value of the element to be added to the Map:

const myMap = new Map([
    [ "myKey", "A string value" ],
    [ "mySecondKey", 500 ],
    [ "myThirdKey", true ]
]);

myMap;
> Map(3) {'myKey' => 'A string value', 'mySecondKey' => 500, 'myThirdKey' => true}

Again, a Map object differs from an object literal in that both the values and the keys can take any data type and value:

const notAFunction = () => console.log( "function" );
const myMap = new Map([
  [ null, 0 ],
  [ false, "This is false" ],
  [ undefined, "No defined value" ],
  [ NaN, "Not a number" ]
]);

myMap;
> Map(4) {null => 0, false => 'This is false', undefined => 'No defined value', NaN => 'Not a number'}

To get, set, or delete Map elements, use the methods inherited from the Map constructor:

const myMap = new Map();

myMap;
> Map(0)

myMap.set( "myKey", "My value." );

myMap.has( "myKey" );
> true

myMap.get( "myKey" );
"My value."

myMap.delete( "myKey" );

myMap;
> Map(0)

Keys in a Map are unique, meaning that setting an identical key overwrites the previously stored key-value pair:

const myMap = new Map([ [ "myKey", "A string value" ] ]);

myMap.set( "myKey", 500 );

myMap;
> Map(1) {'myKey' => 500}

As with objects, you can assign a Map to a variable declared with const and then modify that Map. However, as with other use cases of const, you can't alter or delete the variable itself:

const myMap = new Map();
myMap.set( "myKey", "A string value" );

myMap;
> Map(1) {'myKey' => 500}

WeakMap

A WeakMap is a map that holds "weak" references, which must be references to Objects or Symbols that haven't been added to the global Symbol registry.

To create a WeakMap, use the WeakMap() constructor:

const myWeakMap = new WeakMap();

myWeakMap;
> WeakMap(0)

The WeakMap syntax is similar to Map, but WeakMaps aren't iterable, and trying to use any value other than an object or symbol as a key causes a syntax error. When no references to a key exist outside the WeakMap, that object or symbol, and the associated value in the WeakMap, are both eligible for garbage collection.

This allows for use cases such as storing metadata associated with an object in a WeakMap, using the reference to the object as the key. If no other references exist to this Object, and the Object is removed from memory, the associated metadata is also removed.

Set

A Set is an iterable collection of unique values somewhat similar to an array, though a Set can only contain unique values. As with a Map, iterating over a Set preserves the order elements were added to it.

To create a Set, use the Set() constructor:

const mySet = new Set();

mySet;
> Set []

You can also create a Set from an Array literal:

const mySet = new Set([ 1, 2, 3 ]);

mySet;
> Set(3) [ 1, 2, 3 ]

Because a Set doesn't allow duplicate elements, when a Set is created from an array containing multiple instances of the same value, it only retains the first instance of that value:

const mySet = new Set([ 1, 2, 3, 2 ]);

mySet;
> Set(3) [ 1, 2, 3 ]

To add or remove elements from a Set, use the methods inherited from the Set constructor. These methods act on an element based on the value of the element itself, instead of referencing an index:

const mySet = new Set();

mySet.add( "My value." );

mySet;
> Set [ "My value." ]

mySet.has( "My value." );
> true

mySet.delete( "My value." );

mySet;
> Set []

Though Sets aren't indexed collections, and they're not intended to be used as such, the elements in a Set are iterated over in order of insertion. Attempts to add a duplicate element value to a Set are skipped, preserving the original insertion order:

const mySet = new Set([ 1, 2, 3 ]);

mySet;
> Set(3) [ 1, 2, 3 ]

mySet.add( 2 );
> Set(3) [ 1, 2, 3 ]

To create an Array from a Set, use either the Array.from() method or spread syntax:

const mySet = new Set([ 1, 2, 3 ]);
const myArray = Array.from( mySet );

myArray;
> Array(3) [ 1, 2, 3 ]

[ ...mySet ];
> Array(3) [ 1, 2, 3 ]

WeakSet

WeakSet is a set that contains only garbage-collectable values, such as references to Objects, or Symbols that haven't been added to the global Symbol registry.

To create a WeakSet, use the WeakSet() constructor:

const myWeakSet = new WeakSet();

myWeakSet;
> WeakSet []

The WeakSet syntax is similar to Set, though a WeakSet isn't iterable, and trying to add any value other than an object or symbol causes a syntax error. As with WeakMap, when no other references to a value referenced by a WeakSet exist, that value becomes eligible for garbage collection.

This allows for use cases such as aggregating a single, iterable collection of related objects. If no other references exist to an Object referenced by the WeakSet, the associated element is also removed from the WeakSet.

Check your understanding

Given the following:

        const myMap = new Map([ [ "myKey", "My string" ] ]);
        myMap.set( "myKey", 100 );
      

What does myMap return?

100
undefined
"My string"