All Articles

Exploring ES6 data structures

Up & until ES5, arrays and objects have been the primary mechanism for creating data structures in JS. With the introduction of ES6 specification, some new and useful data structure abstractions have been added.

We’ll be looking at

Map

If you’ve worked with JS objects, which are the primary mechanism for creating key/value pairs, then you are already familiar with maps.

const person = {
  name: 'John Doe',
  age: 30
};

The main limitation with normal objects is that keys have to be of string type or an ES6 Symbol.

With ES6 Maps objects can also be used as keys. The [] bracket syntax has been replaced in favour of set and get .

* Working with Map *

const foo = { bar: 'baz' };

const person = new Map();
person.set('name', 'John Doe');
person.set('age', 30);
person.set(foo, { hello: 'world' }); // notice that object is used as a key
person.get(foo); // {'hello': 'world'}

Map comes with a handy helper has(...) which returns a boolean asserting whether a value has been associated to the key in the Map object or not.

person.has(foo); // true
person.has('foo'); // false

With normal objects one would use delete keyword to delete a property on an object. On a Map, we use delete(...) on the map object which returns true if the key exists and when its deleted, and false if not.

person.delete(foo); // true
person.delete(foo); // false - because foo has been deleted already

Use clear() to clear all key-value pairs on the map object.

person.clear(foo);

To get the list of keys, use keys(), which returns an iterator over the keys in the map:

const foo = { bar: 'baz' };

const person = new Map();
person.set('name', 'John Doe');
person.set('age', 30);
person.set(foo, { hello: 'world' });

const keys = [...person.keys()];

person.get(keys[0]); // John Doe
person.get(keys[1]); // 30
person.get(keys[2]); // {'hello': 'world'}

We could also use entries(), the default map iterator, on the map object with the good old for-of loop.

// Assuming we use the same person Map from above
for (let [key, val] of person.entries()) {
  console.log(`${key} = ${val}`);
}

// Output
// name = John Doe
// age = 30
// {'bar': 'baz'} = {'hello': 'world'}

Map API MDN Docs


WeakMap

A WeakMap works in the same way as Map but only allows objects as keys.

It mainly differs underneath, in how the memory is allocated (specifically Garbage Collection). In WeakMap the keys (objects only) are weakly referenced meaning that if the key object is GC’d then the entry in the weakmap is also removed. This behaviour is particularly useful if you are dealing with objects that you don’t have complete control of like a DOM element.

const person = {
  name: 'John Doe',
  age: 30
};

const obj = {
  key1: {
    id: 1
  }
};

const personMap = new WeakMap();
personMap.set(obj.key1, person);

personMap.set('hello', 'world'); // TypeError: WeakMap key must be an object

personMap.has(obj.key1); // true
delete obj.key1; // true
personMap.has(obj.key1); // false because of weak reference on key1

Other thing to note is that WeakMap doesn’t have clear() method like Map.

WeakMap API MDN Docs


Set

The mathematical definition of a Set.

A set is a well-defined collection of distinct objects, considered as an object in its own right.

In ES6 a Set is collection of unique values (duplicates) are ignored. A set can contain primitve values like strings, numbers, boolean and also complex values like objects and other ES6 data structures (Maps, Sets, etc).

* Working with Set *

A Set can be created by invoking the Set() constructor. Additionally an array of values can be passed to initialize it. Similar to the set() method on a Map, Set has an add() method to add values but doesn’t have a get(...) method.

const set1 = new Set(['x', 'x', 'y', 'y', 'z', 'z', { hello: 'world' }]);
const set2 = new Set();
set2
  .add('x')
  .add('y')
  .add('z')
  .add({ hello: 'world' });

A Set has keys() and values() iterator which yields a list of unique values in the set.

const set1 = new Set(['x', 'y', 'z', { hello: 'world' }]);
const keys = [...set1.keys()];
const values = [...set1.values()];

console.log(keys[0]); // x
console.log(values[0]); // x

keys[1] === values[1]; // true

for (let val of set1.values()) {
  console.log(val);
}

// Output
// x
// y
// z
// {'hello': 'world'}

Use delete(...) to remove an entry from a Set and clear() to remove all entries in the Set.

const set1 = new Set(['x', 'y', 'z', { hello: 'world' }]);
set1.delete('x'); // true
set1.delete('p'); // false - as p doesn't exist
set1.clear();
[...set1.keys()].length; // 0

Set API MDN Docs


WeakSet

WeakSet is similar to a Set, but it holds its values weakly, meaning if the value object is GC’d then the entry is also removed from the weakset object. Another important distinction is that a WeakSet can contain only object values, primitive values like string, number, boolean are not allowed.

const obj = { id1: { hello: 'world' } };
const set1 = new WeakSet([obj.id1]);

set1.add('x'); // TypeError: WeakSet value must be an object

set1.has(obj.id1); // true
delete obj.id1; // true
set1.has(obj.id1); // false

WeakSet API MDN Docs


Typed Array

A Typed Array is a chunk of memory with a typed view inside, with array like access. Each entry in a Typed Array is a raw binary value in one of a number of supported formats, from 8-bit integers to 64-bit floating-point numbers. They provide support for arbitrary byte-based data structures to implement network protocols, cryptographic algorithms, file format manipulations, efficiently pass data to WebGL etc.

* Working with Typed Array *

const buff = new ArrayBuffer(32); // allocates 32 bytes of memory
buff.byteLength; // 32
buff[0] = 10;
buff[1] = 20;
buff[2] = buff[0] + buff[1]; // 30

// Floating point arrays.
var f64 = new Float64Array(8);
var f32 = new Float32Array(16);

// Signed integer arrays.
var i32 = new Int32Array(16);
var i16 = new Int16Array(32);
var i8 = new Int8Array(64);

// Unsigned integer arrays.
var u32 = new Uint32Array(16);
var u16 = new Uint16Array(32);
var u8 = new Uint8Array(64);
var pixels = new Uint8ClampedArray(64); // clamps input values between 0 and 255

Typed arrays shouldn’t be confused with normal arrays. Array.isArray() on a typed array return false. Also, not all the methods on normal arrays are available on typed arrays.

Typed Array API MDN Docs


Reference