Title description:

Introduce the difference between Set, Map, WeakSet and WeakMap?

Problem solving:

  • Idea 1:

Set and Map are mainly used in data reorganization and data storage

A Set is a data structure called a collection, and a Map is a data structure called a dictionary

1. Set

A new data structure added in ES6 is similar to an array, but the members are unique and unordered, with no duplicate values.

A Set is itself a constructor that generates a Set data structure.

new Set([iterable])Copy the code

Here’s an example:

const s = new Set() [1, 2, 3, 4, 3, 2, 1]. ForEach (x => s.dd (x)) for (let I of s) {console.log(I) // 1 2 3 4} 1] [... new Set(arr)] // [1, 2, 3]Copy the code

The Set object allows you to store a unique value of any type, either a primitive value or an object reference.

When you add a value to a Set, no type conversion occurs, so 5 and “5” are two different values. The algorithm used to determine whether two values are different inside a Set is called “same-value-zero equality.” It is similar to the exact equality operator (===), with the main difference that NaN is equal to itself, whereas the exact equality operator assumes NaN is not equal to itself.

let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set {NaN}

let set1 = new Set()
set1.add(5)
set1.add('5')
console.log([...set1])    // [5, "5"]Copy the code
  • Set instance properties

Constructor: a constructor

Size: number of elements

let set = new Set([1, 2, 3, 2, 1])

console.log(set.length)    // undefined
console.log(set.size)    // 3Copy the code

  • Set instance method

Operation Method Add (value) : Adds a value, which is equivalent to an array push

Delete (value) : deletes the value in the collectionCopy the code
Has (value) : Determines whether a value exists in the setCopy the code
Clear () : Clears the collectionCopy the code
let set = new Set()
set.add(1).add(2).add(1)

set.has(1)    // true
set.has(3)    // false
set.delete(1)
set.has(1)    // falseCopy the code

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

const items = new Set([1, 2, 3, 2]) const array = Array.from(items) console.log(array) // [1, 2, 3] / / or const arr = [items]... the console. The log (arr) / / [1, 2, 3]Copy the code

Traversal method (traversal order is insertion order)

Keys () : Returns an iterator containing all the keys in the collectionCopy the code
Values () : Returns all worthy iterators in a containing collectionCopy the code
Ntries () : Returns a key-value iterator containing all elements of a Set objectCopy the code
ForEach (callbackFn, thisArg) : Used to perform a callbackFn operation on a collection member. If thisArg is provided, this in the callback will be the thisArg argument with no return valueCopy the code
let set = new Set([1, 2, 3])
console.log(set.keys())    // SetIterator {1, 2, 3}
console.log(set.values())    // SetIterator {1, 2, 3}
console.log(set.entries())    // SetIterator {1, 2, 3}

for (let item of set.keys()) {
  console.log(item);
}    // 1    2     3
for (let item of set.entries()) {
  console.log(item);
}    // [1, 1]    [2, 2]    [3, 3]

set.forEach((value, key) => {
    console.log(key + ' : ' + value)
})    // 1 : 1    2 : 2    3 : 3
console.log([...set])    // [1, 2, 3]Copy the code

Set can be traversed by default, and the default iterator generator is the values() method

Set.prototype[Symbol.iterator] === Set.prototype.values    // trueCopy the code

Therefore, Set can use map and filter methods

let set = new Set([1, 2, 3])
set = new Set([...set].map(item => item * 2))
console.log([...set])    // [2, 4, 6]

set = new Set([...set].filter(item => (item >= 4)))
console.log([...set])    //[4, 6]Copy the code

Therefore, sets are easy to implement (Intersect), Union, Difference

let set1 = new Set([1, 2, 3]) let set2 = new Set([4, 3, 2]) let intersect = new Set([...set1].filter(value => set2.has(value))) let union = new Set([...set1, ...set2]) let difference = new Set([...set1].filter(value => ! set2.has(value))) console.log(intersect) // Set {2, 3} console.log(union) // Set {1, 2, 3, 4} console.log(difference) // Set {1}Copy the code

2. WeakSet

WeakSet objects allow you to store weak reference objects in a collection

The difference between WeakSet and Set:

  • WeakSet can only store object references, not values, while Set objects can
  • The object values stored in the WeakSet object are weakly referenced, that is, the garbage collection mechanism does not consider the application of WeakSet to the object. If there is no other variable or attribute referencing the object value, the object will be garbage collected (not considering the object still exists in the WeakSet), so, The number of member elements in the WeakSet object depends on whether the garbage collection mechanism is running. The number of members before and after the operation may be inconsistent. After the end of traversal, some members may not be taken (recycled by the garbage), and the WeakSet object cannot be traversed (ES6 specifies that WeakSet cannot be traversed). There’s no way to get all the elements it contains

Any object that has an Iterable interface can be used as an argument

Const arr = [[1, 2], [3,4]] const WeakSet = new WeakSet(arR) console.log(Weakset) // {[[1,2], [3,4]}Copy the code

Methods:

  • Add (value) : Add an element value to the WeakSet object
  • Has (value) : Determines whether a Value is included in a WeakSet object
  • Delete (value) : deletes the value of the element
  • Clear () : Clears all elements, noting that this method is deprecated
var ws = new WeakSet()
var obj = {}
var foo = {}

ws.add(window)
ws.add(obj)

ws.has(window)    // true
ws.has(foo)    // false

ws.delete(window)    // true
ws.has(window)    // falseCopy the code

3. Map

Differences between sets and dictionaries:

  • Common: Collections and dictionaries can store values that are not duplicated
  • Differences: Collections store elements as [value, value], dictionaries as [key, value]
const m = new Map()
const o = {p: 'haha'}
m.set(o, 'content')
m.get(o)    // content

m.has(o)    // true
m.delete(o)    // true
m.has(o)    // falseCopy the code

Any data structure that has an Iterator interface and each member is a two-element array can be taken as an argument to the Map constructor, for example:

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') // 3Copy the code

Returns undefined if an unknown key is read.

new Map().get('asfddfsasadf')
// undefinedCopy the code

Note that only references to the same object are treated as the same key by the Map structure. Be very careful about this.

const map = new Map();

map.set(['a'], 555);
map.get(['a']) // undefinedCopy the code

The set and get methods in the above code appear to be for the same key, but in fact they are two values, the memory address is different, so the get method cannot read the key, return undefined.

Map keys are actually bound to memory addresses. As long as the memory addresses are different, they are regarded as two keys. This solves the clash problem, so when we extend someone else’s library, we don’t have to worry about our properties having the same name as the original author’s properties if we use objects as keys.

If the Map’s key is a value of a simple type (number, string, Boolean), the Map will treat the two values as one key as long as they are strictly equal, such as 0 and -0 being one key, and true and the string true being two different keys. Also, undefined and NULL are two different keys. Although NaN is not strictly equal to itself, Map treats it as the same key.

let map = new Map();

map.set(-0, 123);
map.get(+0) // 123

map.set(true, 1);
map.set('true', 2);
map.get(true) // 1

map.set(undefined, 3);
map.set(null, 4);
map.get(undefined) // 3

map.set(NaN, 123);
map.get(NaN) // 123Copy the code

Map attributes and methods

Properties:

  • Constructor: a constructor
  • Size: Returns the number of elements contained in the dictionary
const map = new Map([
  ['name', 'An'],
  ['des', 'JS']
]);

map.size // 2Copy the code

Operation method:

  • Set (key, value) : Adds a new element to the dictionary
  • Get (key) : Finds a specific value by key and returns it
  • Has (key) : Checks whether the key exists in the dictionary
  • Delete (key) : removes the corresponding data from the dictionary by key
  • Clear () : Removes all elements from this dictionary

Traversal methods

  • Keys() : Returns all key names contained in the dictionary as iterators
  • Values () : Returns all values contained in the dictionary as iterators
  • Entries () : Returns an iterator for all members
  • ForEach () : Traverses all the members of the dictionary
const map = new Map([
        ['name', 'An'],
        ['des', 'JS']
]);
console.log(map.entries())    // MapIterator {"name" => "An", "des" => "JS"}
console.log(map.keys()) // MapIterator {"name", "des"}Copy the code

The default iterator interface of the Map structure (the symbol. iterator property) is the entries method.

map[Symbol.iterator] === map.entries
// trueCopy the code

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

For forEach, look at an example

const reporter = { report: function(key, value) { console.log("Key: %s, Value: %s", key, value); }}; let map = new Map([ ['name', 'An'], ['des', 'JS'] ]) map.forEach(function(value, key, map) { this.report(key, value); }, reporter); // Key: name, Value: An // Key: des, Value: JSCopy the code

In this case, the this of the forEach method’s callback refers to Reporter

Interconversion with other data structures

1. Turn the Map Array

const map = new Map([[1, 1], [2, 2], [3, 3]])
console.log([...map])    // [[1, 1], [2, 2], [3, 3]]Copy the code

2. Turn the Map Array

const map = new Map([[1, 1], [2, 2], [3, 3]])
console.log(map)    // Map {1 => 1, 2 => 2, 3 => 3}Copy the code

3. Turn the Map Object

Since the key names of Object are strings and the key names of Map are objects, non-string keys are converted to string keys during conversion.

function mapToObj(map) {
    let obj = Object.create(null)
    for (let [key, value] of map) {
        obj[key] = value
    }
    return obj
}
const map = new Map().set('name', 'An').set('des', 'JS')
mapToObj(map)  // {name: "An", des: "JS"}Copy the code

4. Turn the Map Object

function objToMap(obj) {
    let map = new Map()
    for (let key of Object.keys(obj)) {
        map.set(key, obj[key])
    }
    return map
}

objToMap({'name': 'An', 'des': 'JS'}) // Map {"name" => "An", "des" => "JS"}Copy the code

5. Turn the Map JSON

function mapToJson(map) {
    return JSON.stringify([...map])
}

let map = new Map().set('name', 'An').set('des', 'JS')
mapToJson(map)    // [["name","An"],["des","JS"]]Copy the code

6. Turn the Map JSON

function jsonToStrMap(jsonStr) {
  return objToMap(JSON.parse(jsonStr));
}

jsonToStrMap('{"name": "An", "des": "JS"}') // Map {"name" => "An", "des" => "JS"}Copy the code

4. WeakMap

A WeakMap object is a collection of key-value pairs, where the keys are weak reference objects and the values can be arbitrary.

Note that WeakMap weakly references only the key name, not the key value. Key values are still normal references.

In WeakMap, the reference of each key to its referenced object is weak. If there is no other reference and the key references the same object, the object will be garbage collected (the corresponding key becomes invalid). Therefore, the key of WeakMap is not enumerable.

Properties:

  • Constructor: a constructor

Methods:

  • Has (key) : checks whether there is an object associated with the key
  • Get (key) : returns the object associated with the key (undefined)
  • Set (key) : Sets a group of key associated objects
  • Delete (key) : deletes the object associated with the key
let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();

myWeakmap.set(myElement, {timesClicked: 0});

myElement.addEventListener('click', function() {
  let logoData = myWeakmap.get(myElement);
  logoData.timesClicked++;
}, false);Copy the code
  • Set
    • Members are unique, unordered, and non-repetitive
    • [value, value], the key value is the same as the key name (or only the key value, no key name)
    • It can be traversed by the following methods: add, delete and HAS
  • WeakSet
    • Members are objects
    • Members are weak references that can be collected by the garbage collection mechanism and can be used to hold DOM nodes without causing memory leaks
    • Cannot traverse. Methods include add, delete, and has
  • Map
    • It’s essentially a set of key-value pairs, sort of a set
    • You can iterate, you can do a lot of things and you can convert to a lot of different data formats
  • WeakMap
    • Only objects (except null) are accepted as key names, and values of other types are not accepted as key names
    • The key name is a weak reference, and the key value can be arbitrary. The object that the key name points to can be garbage collected. In this case, the key name is invalid and cannot be traversed

6. Extension: Object and Set, Map

1. The Object to Set

// Object
const properties1 = {
    'width': 1,
    'height': 1
}
console.log(properties1['width']? true: false) // true

// Set
const properties2 = new Set()
properties2.add('width')
properties2.add('height')
console.log(properties2.has('width')) // trueCopy the code

2. The Object and the Map

An Object in JS is essentially a collection of key-value pairs.

const data = {};
const element = document.getElementsByClassName('App');

data[element] = 'metadata';
console.log(data['[object HTMLCollection]']) // "metadata"Copy the code

But when a DOM node is used as the key of an Object data, the Object is automatically converted to an Object HTMLCollection. So the Object structure provides string-value correspondence, while Map provides value-value correspondence

  • Idea 2? :

:point_down:~~~~ Feel free to add ** your answers in the comments below.

Read more:

  • New ES2018 features that all qualified JS developers need to know about
  • Set and Map data structures
  • 15,000 words to summarize all the features of ES6

❤️ watch two little things

If you find this article inspiring, I’d like you to do me two small favors:

Share this article with your friends/communication group, let more people see it, progress together, grow together!

Pay attention to the public number “IT square head brother alliance”, the public number background reply “resources” free of charge to get my carefully organized front-end advanced resources tutorial

JS Chinese – front-end advanced resources tutorial www.javascriptC.com

A platform dedicated to helping developers change the world with code, find the top stories in the tech world every day! [JS Chinese – front advanced tutorial resources, appreciate the front front, pay attention to IT flat brother league] (https://www.javascriptc.com)