ES6 new feature summary Set and Map Set

Posted by NathanS on Sat, 18 Dec 2021 04:38:41 +0100

1 Set set

Set: a data structure similar to an array without duplicate values. It is mainly used for array de duplication and string de duplication.

1.1 operation method

methodmeaning
add()Add a value and return the Set structure itself
delete()Delete value, and return a boolean indicating whether the deletion is successful
has()Judge whether the value exists and return a boolean
clear()Clear all values, no return value

Example of using add():

let s = new Set();
s.add(1); //Add a value of 1
console.log(s); //Returns the s structure itself

The result is: set (1) {1}

let s = new Set();
s.add(1).add(2).add(1); //Add three times continuously, of which 1 is added repeatedly
console.log(s); //Output Set structure itself

The result is: set (2) {1, 2}

The above code adds 1 twice, but there is only one 1 in s, so there is no duplicate value in Set. According to the observation, "Set" is added in front of the results of the first two times, and sometimes {} is the result we want, so we can use the expansion operator (...) to expand the value of Set.

let s = new Set();
s.add(1).add(2).add(1); //Add number 3 times for s
console.log(...s) //Expand the value of Set

The output result is: 1 2

The output result is a sequence, which can be turned into an array by adding a [].

let s = new Set();
s.add(1).add(2).add(1); //Add number 3 times for s
console.log([...s]) //Output as array

The output result is: [1, 2]

Use example of delete():

let s = new Set();
s.add(1).add(2); //Two numbers were added to the Set: 1 and 2
console.log("Before deletion:", ...s); //Output 1 2
s.delete(1); //Delete 1
console.log("After deletion:", ...s); //Output 2

The output result is:
Before deletion: 1 2
After deletion: 2

The return value of delete() is to judge whether the number has been deleted successfully. Therefore, in the previous code, the return value of s.delete(1) must be true.

let s = new Set();
s.add(1).add(2); //Two numbers were added to the Set: 1 and 2
console.log(s.delete(1)); //Output the return value after deleting 1

The output result is: true

If you delete a number that does not exist in s, its return value is false.

let s = new Set();
s.add(1).add(2); //Two numbers were added to the Set: 1 and 2
console.log(s.delete(3)); //Output the return value after deleting 3
console.log(...s); //Output s

The result is:
false
1 2

It can be seen from the above results that if a nonexistent number is deleted, its return value is false, but it does not affect the original Set result. The program will not report an error and will normally output the original Set.

has() usage example:

let s = new Set();
s.add(1).add(2); //Add two numbers 1 and 2 to s
console.log(s.has(1)); //Judge whether 1 is included in s
console.log(s.has(3)); //Judge whether 3 is included in s

The result is: true or false

If the value exists in the Set set, the return value is true; If the value does not exist in the Set collection, the return value is false.

clear() usage example:

let s = new Set();
s.add(1).add(2); //Add two numbers 1 and 2 to s
s.clear(); //Clear all values
console.log(s);

The output result is: Set(0) {}

1.2 traversal method

Since Set has only key value but no key name, it can also be said that the key and value are the same (the key and value are the same and can be omitted), and the returned values of keys and values are the same.

let set = new Set();
set.add(1).add(2).add(3); //Add 3 numbers: 1, 2, 3
for (let i of set.keys()) { //Traverse the keys of the set set, and keys() represents the keys
    console.log(i); //Key of output set set
}

The output result is: 1 2 3

let set = new Set();
set.add(1).add(2).add(3); //Add 3 numbers: 1, 2, 3
for (let i of set.values()) { //Traverse the keys of the set set, and keys() represents the keys
    console.log(i); //Key of output set set
}

The output result is: 1 2 3

let set = new Set();
set.add("hello").add("world"); //Add two strings
for (let i of set.entries()) { //Traverse the key value pair of set, and entries() represents the key value pair
    console.log(i); //Output traversal results
}

The output result is:
[ 'hello', 'hello' ]
[ 'world', 'world' ]

Use forEach() to traverse the Set collection.

let set = new Set();
set.add("hello").add("world"); //Add two strings to set
set.forEach((key, val) => { //Traversal keys and values
    console.log(key + "||" + val); //Output keys and values
})

The output result is:
hello||hello
world||world

Set can accept an array as a parameter.

let arr = ["Xiao Hong", "Xiao Ming", "cockroach", "Xiao Ming"];
let set = new Set(arr); //Pass the arr array as a parameter to the set set
console.log(...set); //Output set set

The result is: Xiao Hong, Xiao Ming, Xiao Qiang

[case] Set realizes Union and intersection.

let arr1 = [4, 5, 6];
let arr2 = [5, 6, 7];
let setA = new Set(arr1);
let setB = new Set(arr2);
//Merge sets, merge two sets together, and remove redundant and repeated numbers
let bingji = new Set([...setA, ...setB]);
console.log(...bingji); //Output union results
//Find the intersection, merge the two sets together, find the repeated numbers, and use the filter filter to get the results
//Filter out the values contained together with setB in setA
let jiaoji = new Set([...setA].filter(val => setB.has(val)));
console.log(...jiaoji); //Output intersection results

The result is:
4 5 6 7
5 6

1.3 WeakSet

A WeakSet can only be a collection of objects, not any value of any type.

References to objects in the WeakSet collection are weak references. If there are no other references to objects in the WeakSet, these objects will be garbage collected.

This also means that there is no list of current objects stored in the WeakSet. Because of this, the WeakSet cannot be enumerated. That is, the reference to the object in the WeakSet will not be considered into the garbage collection mechanism, that is, as long as no other object references the object, the object will be recycled, regardless of whether it is in the WeakSet or not.

WeakSet supports add, has and delete methods, but does not support size and keys(), and is not iterative and cannot be traversed.

Add an object to the weakSet and view its return value:

let jack = { name: "jack" }; //jack is an object
let weakSet = new WeakSet();
weakSet.add(jack); //Add an object for the weakSet
console.log(weakSet.has(jack)); //Judge whether the weakSet contains jack and output the return value

The result is: true

Delete the object just added and view the return value:

let jack = { name: "jack" }; //jack is an object
let weakSet = new WeakSet();
weakSet.add(jack); //Add an object for the weakSet
weakSet.delete(jack); //Remove jack from the weakSet
console.log(weakSet.has(jack)); //Judge whether the weakSet contains jack and output the return value

Result: false

Add content other than objects to the WeakSet and view its results:

let jack = { name: "jack" }; //jack is an object
let weakSet = new WeakSet();
weakSet.add(1); //Add a value other than the object to the weakSet

The program will report an error: TypeError: Invalid value used in weak set, because only objects can be stored in the weak set.

Application scenario / benefit of WeakSet: it is used to store DOM nodes without worrying about memory leakage when these nodes are removed from the document.

2 Map set

2.1 Map overview

JavaScript objects are essentially a collection of key value pairs (Hash structure), but traditionally they can only use strings as keys. This brings great restrictions to its use.

To solve this problem, ES6 provides a Map data structure. It is similar to an Object and is also a collection of key value pairs, but the range of "key" is not limited to strings, and various types of values (including objects) can be used as keys. In other words, the Object structure provides the correspondence of "string value" and the Map structure provides the correspondence of "value value", which is a more perfect Hash structure implementation.

The Map type in ES6 is an ordered list storing many key value pairs, in which the key name and corresponding value support all data types. The equivalence of key names is determined by calling object Is () method, so the number 5 and the string "5" will be determined as two types and can appear in the program as two independent keys, which is different from the object, because the attribute name of the object will always be cast into the string type.

be careful:
1. With one exception, the Map collection treats + 0 and - 0 as equal, which is the same as object Is () results are different.
2. If the data structure of "key value pair" is required, Map is more suitable than Object and has extremely fast search speed

2.2 basic methods and attributes

1. Attribute: size, returns the number of elements in the Map

2. Basic method

methodmeaning
set()Add data to the Map and return the added Map (assigning values to existing keys will overwrite the previous values)
get()Get the value of a key and return the value corresponding to the key. If there is no key, return undefined
has()Detects whether a key exists and returns a Boolean value
delete()Delete a key and its corresponding value, return Boolean value, success: true; Failed: false
clear()Clear all values and return undefined

Usage example of size and set():

let map = new Map();
map.set("name", "Orange cat is not fat"); //Add data to map
map.set("age", 2); //Add data to map
console.log(map.size); //Number of elements in the output map (length)
console.log(map); //Output map after adding data

The output result is:
2
Map(2) {'name' = > 'orange cat is not fat', 'age' = > 2}

Use example of get():

let map = new Map();
map.set("name", "Orange cat is not fat"); //Add data to map
map.set("age", 2); //Add data to map
console.log(map.get("name")); //Output the value corresponding to name
console.log(map.get("address")); //undefined when there is no key

The output result is:
Orange cat is not fat
undefined

has() usage example:

let map = new Map();
map.set("name", "Orange cat is not fat"); //Add data to map
map.set("age", 2); //Add data to map
console.log(map.has("name")); //Determine whether the map contains name
console.log(map.has("address")); //Determine whether the map contains address

The output result is:
true
false

Use example of delete():

let map = new Map();
map.set("name", "Orange cat is not fat"); //Add data to map
map.set("age", 2); //Add data to map
console.log(map.delete("name")); //Delete name in map
console.log(map.delete("address")); //Delete address in map

The output result is:
true
false

clear() usage example:

let map = new Map();
map.set("name", "Orange cat is not fat"); //Add data to map
map.set("age", 2); //Add data to map
console.log(map); //Output map after adding value
console.log(map.clear()); //Output the return value after clearing all values
console.log(map); //Output map after clearing value

The output result is:
Map(2) {'name' = > 'orange cat is not fat', 'age' = > 2}
undefined
Map(0) {}

2.3 traversal method

Note: the traversal order of the Map is the insertion order

methodmeaning
keys()Get all key s of Map
values()Get all values of Map
entries()Get all Map members
forEach()Traverse all members of the Map
//Create a map collection and pass in a two-dimensional array
const map = new Map([
    ["F", "no"],
    ["T", "yes"]
])
console.log(map); 

The output result is: Map(2) {'F' = > 'no','T '= >' yes'}

Examples of using keys():

//Create a map collection and pass in a two-dimensional array
const map = new Map([
    ["F", "no"],
    ["T", "yes"]
])
for (let key of map.keys()) { //Key traversing map
    console.log(key); //Key to output map
}

The output result is: F T

Examples of using values():

//Create a map collection and pass in a two-dimensional array
const map = new Map([
    ["F", "no"],
    ["T", "yes"]
])
for (let value of map.values()) { //Traversal map values
    console.log(value); //Output map value
}

The output result is:
no
yes

Examples of using entries():

//Create a map collection and pass in a two-dimensional array
const map = new Map([
    ["F", "no"],
    ["T", "yes"]
])
for (let item of map.entries()) { //Traverse all map members
    console.log(item); //Output all map members
}

The output result is:
[ 'F', 'no' ]
[ 'T', 'yes' ]

Or:

//Create a map collection and pass in a two-dimensional array
const map = new Map([
    ["F", "no"],
    ["T", "yes"]
])
for (let [key, value] of map.entries()) { //Traverse map members
    console.log(key, value); //Output map member
}

The output result is:
F no
T yes

Or:

const map = new Map([
    ["F", "no"],
    ["T", "yes"]
])
// Equivalent to using map entries()
for (let [key, value] of map) { //Traverse map members
    console.log(key, value); //Output map member
}

The output result is:
F no
T yes

2.4 convert to array

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

//Create a map collection
const map = new Map([
    [1, "one"],
    [2, "two"],
    [3, "three"]
])
//Convert the key of the map into an array
console.log(...map.keys()); //1 2 3
//Convert the value of the map into an array
console.log(...map.values()); //one two three
//Convert the map object into an array
console.log(...map.entries()); //[ 1, 'one' ] [ 2, 'two' ] [ 3, 'three' ]
//Convert map to an array
console.log(...map); //[ 1, 'one' ] [ 2, 'two' ] [ 3, 'three' ]

2.5 Map traversal and filtering

Combined with the map method and filter method of array, the traversal and filtering of map can be realized.

const map0 = new Map();
map0.set(1, "a"); //Add data for map0
map0.set(2, "b"); //Add data for map0
map0.set(3, "c"); //Add data for map0

//Use of filter()
const map1 = new Map(
    //Filter out the key less than 3 in map0
    [...map0].filter(([k, v]) => k < 3)
);
console.log(map1); //Map(2) { 1 => 'a', 2 => 'b' }

//Use of map()
const map2 = new Map(
    //Change the key of the member in map0 to 2 times, and add "" in front of the value
    [...map0].map(([k, v]) => [k * 2, "_" + v])
)
console.log(map2); //Map(3) { 2 => '_a', 4 => '_b', 6 => '_c' }

2.6 forEach()

const map = new Map([[1, 'one'], [2, 'two'], [3, 'three']]);
map.forEach((value, key, map) => {
    console.log(value, key, map);
})

The output result is:
one 1 Map(3) { 1 => 'one', 2 => 'two', 3 => 'three' }
two 2 Map(3) { 1 => 'one', 2 => 'two', 3 => 'three' }
three 3 Map(3) { 1 => 'one', 2 => 'two', 3 => 'three' }

2.7 WeakMap

WeakMap is a collection of weakly referenced maps and is also used to store weak references to objects. The key name in the WeakMap collection must be an object. If a non object key name is used, an error will be reported.

The weak references of these objects are saved in the collection. If there are no other strong references besides the weak references, the garbage collection mechanism of the engine will automatically recycle this object and remove the key value pairs in the WeakMap collection. However, only the key name of the collection complies with this rule. If the value corresponding to the key name is an object, it saves a strong reference to the object and will not trigger the garbage collection mechanism.

1. Using the WeakMap collection
The WeakMap type in ES6 is an unordered list that stores many key value pairs. The key name of the list must be an object of non null type, and the value corresponding to the key name can be of any type.

The interface of WeakMap is very similar to that of Map. Data is added through the set() method and obtained through the get() method.

let map = new WeakMap();
const o1 = {}; //o1 is an empty object
const o2 = function () { }; //o2 is an empty function
map.set(o1, o2); //Add data to the map. The key and value can be any object, or even another WeakMap object
map.set(o2, "Orange cat is not fat"); //Add data to map
console.log(map.get(o1)); //[Function: o2]
console.log(map.get(o2)); //Orange cat is not fat

The size property is not supported for the WeakMap collection, so it cannot be verified that the collection is empty.

2. Methods supported by the WeakMap collection

methodmeaning
has()Detects whether the given key exists in the collection
delete()Removes the specified key value pair

has() usage example:

let map = new WeakMap();
const o1 = {}; //o1 is an empty object
const o2 = function () { }; //o2 is an empty function
map.set(o1, o2); //Add data to the map. The key and value can be any object, or even another WeakMap object
map.set(o2, "Orange cat is not fat"); //Add data to map
console.log(map.has(o1)); //Judge whether the map contains o1 and true
console.log(map.has(o3)); //Judge whether the map contains o3, and the program reports an error. ReferenceError: o3 is not defined

Use example of delete():

let map = new WeakMap();
const o1 = {}; //o1 is an empty object
const o2 = function () { }; //o2 is an empty function
map.set(o1, o2); //Add data to the map. The key and value can be any object, or even another WeakMap object
map.set(o2, "Orange cat is not fat"); //Add data to map
console.log(map.delete(o1)); //If o1 in the map is deleted, true will be returned if the deletion is successful
console.log(map.has(o1)); //Determine whether the map contains o1

The output result is: true or false

3. Purpose of the WeakMap collection

  • Store DOM elements
    <button id="btn">click</button>
    <script>
        //Get button element
        let myElement = document.getElementById("btn");
        let myWeakmap = new WeakMap();
        //Add data for myWeakmap
        myWeakmap.set(myElement, { timesClicked: 0 });
        //Add a click event for the button
        myElement.addEventListener("click", function () {
            //Gets the value whose myWeakmap key is myElement
            let logoData = myWeakmap.get(myElement);
            //Click once plus 1
            logoData.timesClicked++;
            //Output hits
            console.log(logoData.timesClicked);
        })
    </script>


In the code, myElement is a DOM node that updates the status whenever a click event occurs. We put this state as a key value in the WeakMap, and the corresponding key name is myElement. Once the DOM node is deleted, the state will disappear automatically, and there is no risk of memory leakage

  • Register the listener object that listens to events, which is very suitable to be implemented with WeakMap.
    <button class="element1">Button 1</button>
    <button class="element2">Button 2</button>
    <script>
        //Get element
        let element1 = document.querySelector(".element1");
        let element2 = document.querySelector(".element2");
        const listener = new WeakMap();
        //Add two data for listener
        listener.set(element1, "handler1");
        listener.set(element2, "handler2");
        //Add a click event for element1
        element1.addEventListener("click", function () {
            console.log(listener.get(element1));
        })
        //Add a click event for element2
        element2.addEventListener("click", function () {
            console.log(listener.get(element2));
        })
    </script>


The listening function is placed in the WeakMap. Once the DOM object disappears, the listener function bound to it will also disappear automatically.

  • Deploy private properties
    When we create objects, we usually write a constructor.
function Person(name) {
    this._name = name;
}
Person.prototype.getName = function () {
    return this._name;
}

However, when creating a Person object, we can directly access the name attribute:

const person = new Person("Orange cat is not fat");
console.log(person._name); //Orange cat is not fat

Instead of allowing users to directly access the name attribute, we can wrap the name as a private attribute using the following method.

let Person = (function () {
    let privateData = new WeakMap();
    function Person(name) { //Define a function with the parameter name
        privateData.set(this, { name: name }); //Set data for privateData
    }
    Person.prototype.getName = function () { //Set getName function
        return privateData.get(this).name; //Gets the name of the value of the name key in privateData
    }
    return Person;
}()); //() called after the function is set
const person = new Person("Orange cat is not fat");
console.log(person.getName());

Topics: Javascript Front-end