Article source: juejin.cn/post/699310… Author: Xiao Cheng

Map

Why Map?


1. Traditional object structure

A Map is essentially a collection of key-value pairs. Compared to the traditional object structure, the traditional object can only use string as the key name, which causes a great limitation in use.

Const element = document.querySelector('.node') console.log(element) // Outputs the div.node object Console.log (element.toString()) // The dot operator cannot have Spaces, so use parentheses to assign data[Element] = 'objectData' // print objectData, [Object HTMLDivElement] key name console.log(data['[Object HTMLDivElement]'])Copy the code

In the above code, we created an object and took a node object as its key name, and carried out the code test. First, we verified the obtained Element node as an object, and then determined the result after the toString method conversion, successfully output value objectData with this value as the key name.

The above code demonstrates that the key names of traditional objects are converted to a string type using the toString method

Note: we cannot access object members with Spaces in their keys, such as data.ab c. This is an error. We can access it as data[‘ab c’]

2. The structure of the Map

A Map is similar to an Object, but the key names are not limited to strings. It can be said that the Object structure provides key-value mappings, while the Map structure provides value-value mappings. Therefore, the Map structure is better than traditional objects.

const dataMap = new Map()
const element = document.querySelector('.node')
dataMap.set(element,'objectData')
console.log(dataMap.get(element))
console.log(dataMap)
Copy the code

In the above code, we pass the element object directly to the value, successfully using the object as the key name, making up for the traditional object.

3. The characteristics of the Map
  1. The Map contains no keys by default; all keys are added by themselves. Unlike the Object prototype chain, which has a default key.
  2. Map keys can hold any type of data, even functions.
  3. The number of Map key-value pairs can be easily obtained by using the size property, whereas Object needs to be calculated manually.
  4. Map performs better than Object when key/value pairs are frequently added or deleted.
4. When to use Map
  1. If you want to add a key name that conflicts with the default key name on Object, but do not want to rename it, use Map.
  2. Use Map when you need data types other than String and Symbol for key values.
  3. There are a lot of key-value pairs, and sometimes you need to count them, using a Map.
  4. Map is used when key pairs need to be added or deleted frequently.

Map instance attributes and methods


  1. set

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

Multiple sets of data can also be set in chained form

  1. get

The get method is used to get the value of the key. If the passed key does not exist, undefined is returned

  1. has

This method returns a Boolean value to determine whether the passed key exists in the current Map object

4. Delete Deletes the passed key, returning true or false on failure.

  1. clear

Clears all members, no return value.

Traversal methods


For… Of and forEach. Because Map instances maintain the insertion order of key-value pairs, traversal can be performed based on the insertion order

  1. for… of
  • Keys (): returns a traverser for key names
  • Values (): Iterator that returns key values
  • Entries (): Returns a traverser for key and value pairs
  • ForEach (): Iterates through each member using the callback function

map.entries()

There is an iterator in a Map instance that generates data in the form of [key,value] in insert order.

We can obtain this iterator using the entries method to use for… Of traverses

You can do that

Entries are the default iterator, so you can extend or use a Map instance

Adopt extended operation

map.values()

map.keys()

forEach()

Map type conversion


  1. Map is converted to an array
let map = new Map(a)let arr = [...map]
Copy the code
  1. Arrays are converted to maps
let map = new Map(arr)
Copy the code
  1. Turn the Map object
let obj = {}
for(let [k,v] of map){
     obj[k] = v
 }
Copy the code
  1. Object to Map
for(let k of Object.keys(obj)){
    map.set(k,obj[k])
}
Copy the code

WeakMap

What is a WeakMap


WeakMap is a new collection type in ES6 called ‘weak mapping’. It is a sibling of Map. The difference between Map and Map is that the API is the same as Map

The characteristics of WeakMap


1. WeakMap can only use objects as key names

Only objects (except null) are accepted as key names. Values of other types are not accepted as key names.

2. The object referenced by the key name of WeakMap is a weak reference

The first thing we need to know is what is a strong reference and what is a weak reference

Strong reference

const e1 = document.getElementById('foo')
const e2 = document.getElementById('bar')
const arr = [
    [e1,'foo'],
    [e2,'bar'],
];
Copy the code

In the above code, E1 and e2 are two objects. Add some text to these two objects through the ARR array. But this creates a strong reference by ARR to E1 and E2. That’s the difference. When we no longer need the two objects, we must manually remove the reference and touch the ARR’s reference relationship to the two objects, otherwise the garbage collection mechanism will not free the memory occupied by E1 and E2. Because arR still has references to objects.

arr[0] = null;
arr[1] = null;
Copy the code

A weak reference

A reference that cannot be guaranteed that its referenced object will not be collected by the garbage collector. An object that is referred to only by weak references is considered unreachable and can therefore be reclaimed at any time. That is, when we create a weakly referenced object, we can wait for it to be collected by the garbage collector.

In general, WeakMap maintains a weak reference to the object referenced by the key name, that is, the garbage collection mechanism does not take that reference into account. As soon as all other references to the referenced object are cleared, the garbage collection mechanism frees the memory occupied by the object. In other words, once it is no longer needed, the key name object and the corresponding key value pair in WeakMap will disappear automatically, and there is no need to manually delete the reference.

3. Do not traverse

Because WeakMap has a weak reference relation to the object referenced by the key name, WeakMap internal members will depend on whether garbage collection mechanism is implemented. The number of members before and after operation is likely to be different, and the execution of garbage collection mechanism is unpredictable, so it cannot be traversed.

Map is different from WeakMap

  • Map keys can be of any type. WeakMap only accepts objects as keys and does not accept values of other types as keys
  • Map keys are actually bound to memory addresses. If the memory addresses are different, they are treated as two keys. The key of WeakMap is a weak reference, and the object that the key points to can be garbage collected, so the key is invalid.
  • Map can be traversed, while WeakMap cannot be traversed

WeakMap Usage scenarios


1.DOM node metadata
const m = new Map(a)const loginButton = document.querySelector(#login')
m.set(loginButton, {disabled: true})
Copy the code

When the above code is executed, the login button is removed from the DOM tree, but since the Map is strongly referencing the node object, it still holds the reference to the button, causing a memory leak.

const m = new WeakMap(a)const loginButton = document.querySelector(#login')
m.set(loginButton, {disabled: true})
Copy the code

When WeakMap is used, when the node is deleted, the reference count is 0, and it automatically waits for garbage collection mechanism to collect it.

2. Deploy private properties

With weak mapping, internal properties are set as weak reference objects of the instance, and when the instance is deleted, private properties disappear with it, so there is no memory leak

const _counter = new WeakMap(a)const _action = new WeakMap(a)class Countdown{
    constructor(counter,action){
        _counter.set(this,counter)
        _action.set(this,action)
    }
    dec(){
        let counter = _counter.get(this)
        if(counter < 1) return
        counter --
        _counter.set(this,counter)
        if(counter === 0){
            _action.get(this) (the)}}}const c = new Countdown(2.() = >console.log('DONE'))

c.dec()
c.dec()
// DONE

Copy the code
3. Data caching

WeakMap can be used when we need to store some properties and so on without modifying the original object, but we don’t want to manage the data

const cache = new WeakMap(a)function countOwnKeys(obj){
    if(cache.has(obj)){
        return cache.get(obj)
    }else{
        const count = Object.keys(obj).length
        cache.set(obj, count)
        return count
    }
}
Copy the code