Set and Map data structures

Set

ES6 provides a new data structure, Set. It is similar to an array, but the values of the members are unique and there are no duplicate values.

The Set itself is a constructor used to generate the Set data structure.

const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);
}
// 2 3 5 4
Copy the code

The code above adds members to the Set structure using the add() method, which shows that the Set structure does not add duplicate values.

The Set function can take an array (or some other data structure with an Iterable interface) as an argument for initialization.

// const set = new set ([1, 2, 3, 4, 4]); Set [...] / [1, 2, 3, 4] / / two cases of const items = new set ([1, 2, 3, 4, 5, 5, 5, 5)); The items. The size / / / / 5 cases of three const set = new set (document. QuerySelectorAll (' div ')); Set.size // 56 // similar to const set = new set (); document .querySelectorAll('div') .forEach(div => set.add(div)); set.size // 56Copy the code

Remove duplicate members from an array:

// Remove duplicate members from array [...new Set(array)]Copy the code

Remove duplicate characters from a string:

[...new Set('ababbc')].join('')
// "abc"
Copy the code

Properties and methods of a Set instance

Instances of the Set structure have the following properties.

  • Set. The prototype. The constructor: constructor, the default is Set function.
  • Set.prototype.size: Returns the total number of members of a Set instance.

The methods of a Set instance fall into two broad categories: operation methods (for manipulating data) and traversal methods (for traversing members).

  • Set.prototype.add(value) : Adds a value and returns the Set structure itself.
  • Set.prototype.delete(value) : Deletes a value and returns a Boolean value indicating whether the deletion was successful.
  • Set.prototype.has(value) : Returns a Boolean value indicating whether the value is a member of Set.
  • Set.prototype.clear() : Clears all members with no return value.

Examples of these properties and methods are shown below.

s.add(1).add(2).add(2); // notice that 2 is added twice s.size // 2 s.haas (1) // true s.haas (2) // true s.haas (3) // false s.delte (2); s.has(2) // falseCopy the code

The array. from method converts a Set structure to an Array.

const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);
Copy the code

This provides another way to remove duplicate members of an array.

function dedupe(array) {
  return Array.from(new Set(array));
}

dedupe([1, 1, 2, 3]) // [1, 2, 3]
Copy the code

Traversal operation

An instance of a Set structure has four traversal methods that can be used to traverse members.

  • Set.prototype.keys() : iterator that returns key names
  • Set.prototype.values() : iterator that returns key values
  • Set.prototype.entries() : Returns a traverser for key and value pairs
  • Set.prototype.foreach () : Use the callback function to iterate over each member

WeakSet

WeakSet structure is similar to Set, which is also a collection of non-repeating values. However, it differs from Set in two ways.

First, WeakSet members can only be objects, not other types of values.

const ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set
Copy the code

The above code attempts to add a value and a Symbol value to WeakSet, and returns an error because WeakSet can only place objects.

Secondly, the objects in WeakSet are weak references, that is, garbage collection mechanism does not consider WeakSet’s reference to the object, that is to say, if other objects no longer reference the object, then garbage collection mechanism will automatically recover the memory occupied by the object, not considering the object still exists in WeakSet.

Map

JavaScript objects are essentially collections of key-value pairs (Hash structures), but traditionally strings can only be used as keys. This puts a great limit on its use.

const data = {};
const element = document.getElementById('myDiv');

data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
Copy the code

The above code is intended to use a DOM node as the key of the data object, but since objects only accept strings as key names, element is automatically converted to a string.

To solve this problem, ES6 provides Map data structures. It is a collection of key-value pairs similar to objects, but the range of “keys” is not limited to strings. Values of all types (including objects) can be used as keys.

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false
Copy the code

The above code uses the set method of the Map structure to treat the object O as a key of M, then reads the key using the get method, and then deletes the key using the DELETE method.

The example above shows how to add members to a Map. As a constructor, a Map can also take an array as an argument. The members of this array are arrays representing key-value pairs.

Const map = new map ([[' name ', 'zhang'], [' title ', 'the Author]]). Map. The map for the size / / 2. From the (' name ') / / true map. Get (' name ') / / "zhang SAN" map. From the (' title ') / / true map. Get (' title ') / / "Author"Copy the code

The code above specifies two keys name and title when creating a Map instance.

The Map constructor takes an array as an argument.

Const items = [[' name ', 'zhang'], [' title ', 'the Author]]. const map = new Map(); items.forEach( ([key, value]) => map.set(key, value) );Copy the code

In fact, not just arrays, but any data structure with an Iterator interface where each member is a two-element array (see chapter Iterator) can be taken as a parameter to the Map constructor. That is, both sets and maps can be used to generate new maps.

const set = new Set([
  ['foo', 1],
  ['bar', 2]
]);
const m1 = new Map(set);
m1.get('foo') // 1

const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
m3.get('baz') // 3
Copy the code

In the code above, we use a Set object and a Map object, respectively, as arguments to the Map constructor, resulting in a new Map object.

If the same key is assigned more than once, the subsequent value overrides the previous value.

const map = new Map();

map
.set(1, 'aaa')
.set(1, 'bbb');

map.get(1) // "bbb"
Copy the code

The code above assigns key 1 twice in a row, overwriting the previous value.

Instance properties and operation methods

An instance of a Map structure has the following properties and operations.

(1) Size attribute

The size property returns the total number of Map structure members.

const map = new Map();
map.set('foo', true);
map.set('bar', false);

map.size // 2
Copy the code

Prototype set(key, value)

The set method sets the key corresponding to the key name key to value and returns the entire Map structure. If the key already has a value, the key value is updated, otherwise the key is generated.

const m = new Map(); M.et ('edition', 6) // key is string m.et (262, 'standard') // key is numeric m.et (undefined, 'nah') // key is undefinedCopy the code

The set method returns the current Map object, so it can be chained.

let map = new Map().set(1, 'a').set(2, 'b').set(3, 'c');
Copy the code

(3) the Map. The prototype. The get (key)

The get method reads the corresponding key, and returns undefined if the key is not found.

const m = new Map(); const hello = function() {console.log('hello'); }; m.set(hello, 'Hello ES6! ') // keys are functions m.et (hello) // hello ES6!Copy the code

(4) the Map) prototype) from the (key)

The HAS method returns a Boolean value indicating whether a key is in the current Map object.

const m = new Map();

m.set('edition', 6);
m.set(262, 'standard');
m.set(undefined, 'nah');

m.has('edition')     // true
m.has('years')       // false
m.has(262)           // true
m.has(undefined)     // true
Copy the code

(5) the Map. The prototype. The delete (key)

The delete method deletes a key and returns true. If deletion fails, return false.

const m = new Map();
m.set(undefined, 'nah');
m.has(undefined)     // true

m.delete(undefined)
m.has(undefined)       // false
Copy the code

(6) the Map. The prototype. The clear ()

The clear method clears all members with no return value.

let map = new Map();
map.set('foo', true);
map.set('bar', false);

map.size // 2
map.clear()
map.size // 0
Copy the code

Traversal methods

The Map structure natively provides three traverser generating functions and one traversal method.

  • Map.prototype.keys() : iterator that returns key names.
  • Map.prototype.values() : iterator that returns key values.
  • Map.prototype.entries() : Returns a traverser for all members.
  • Map.prototype.foreach () : Iterates through all members of the Map.

A faster way to convert a Map structure into an array structure is to use the extension operator (…). .

const map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

[...map.keys()]
// [1, 2, 3]

[...map.values()]
// ['one', 'two', 'three']

[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]

[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]
Copy the code

Interconversion with other data structures

(1) Map is converted into an array

As mentioned earlier, the most convenient way to turn a Map into an array is to use the extension operator (…). .

const myMap = new Map()
  .set(true, 7)
  .set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]
Copy the code

(2) The array is converted to Map

The array is converted to a Map by passing it to the Map constructor.

new Map([
  [true, 7],
  [{foo: 3}, ['abc']]
])
// Map {
//   true => 7,
//   Object {foo: 3} => ['abc']
// }
Copy the code

(3) Map is converted into an object

If all Map keys are strings, it can be converted to objects losslessly.

function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    obj[k] = v;
  }
  return obj;
}

const myMap = new Map()
  .set('yes', true)
  .set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }
Copy the code

(4) The object is converted to Map

Objects can be turned into maps through Object.entries().

let obj = {"a":1, "b":2};
let map = new Map(Object.entries(obj));
Copy the code

WeakMap

WeakMap structure is similar to Map structure and is also used to generate a set of key-value pairs.

WeakMap differs from Map in two ways.

First, WeakMap only accepts objects as key names (except null) and does not accept other types of values as key names.

const map = new WeakMap();
map.set(1, 2)
// TypeError: 1 is not an object!
map.set(Symbol(), 2)
// TypeError: Invalid value used as weak map key
map.set(null, 2)
// TypeError: Invalid value used as weak map key
Copy the code

Second, the object to which the key name of WeakMap points is not included in the garbage collection mechanism.

WeakMap is designed so that sometimes we want to put some data on an object, but that creates a reference to that object.

Most of this article comes from the following ES6 tutorial:

Getting started with ECMAScript 6

ECMAScript 6 profile