This is the 5th day of my participation in the August More Text Challenge

Map

Map objects store key-value data in the order in which they are inserted. Any data type can be used as keys or values.

Similar to Object, each key must be unique, and a value comparison is performed if the key’s data type is a primitive data type, and a reference comparison is performed for the Object type.

Instance attributes

  • sizeRead-only property that returns the number of key-value pairs

methods

  • set(key, value)Add key-value pairs
  • get(key)Returns the value associated with this key
  • clear()Remove all key-value pairs
  • delete(key)Delete key-value pairs equal to this key
  • has(value)Returns whether the value is included
  • entries()Returns an iterator containing all key-value pairs in the Map in insertion order, with each element of the iterator being[key, value]Array of form
  • forEach(callbackFn, thisArg)Callback is executed with the key and value of each key-value pair as the first and second arguments, respectively, in insertion order
  • keys()Returns an iterator containing all the keys in the Map in insertion order
  • values()Returns an iterator containing all the values in the Map in insertion order

Map vs Object

Differences between the overview

  • Map keys can be any data type, Object keys can only be strings or symbols
  • Map can obtain the number of elements by size, Object does not
  • The Map itself is an iterator that can be iterated directly. Object requires static methods on Object objects (keys,values,entries) to iterate
  • Map serialization (JSON.stringify) becomes a common Object, resulting in the loss of its own data type, which needs to be implemented by itself. Similarly, string parsing into JSON objects cannot support Map

The insert

Here’s the test code:

var m = new Map(a)var now = performance.now()
for(let i = 0; i<10000; i++) {
    m.set('m'+i, i)
}
console.log(performance.now() - now)

var o = {}
var now = performance.now()
for(let i = 0; i<10000; i++) {
    o['o'+i] = i
}
console.log(performance.now() - now)
Copy the code

When the number of inserts is 10,000, the difference between Map and Object is not significant, and they are basically within 3-5ms.

When reaching 100,000, the average length of Map is around 50ms, most of which fall within the range of 45-55ms. The average length of Object is about 60ms, most of which fall in the range of 50-70ms.

When reaching 1 million, the average length of Map is around 590ms, most of which fall within the range of 500-700ms. The average duration of Object is about 650ms, most of which falls in the range of 550-750ms, and occasionally exceeds 850ms.

When reaching 5 million, the average length of Map is 3542.4ms, most of which fall in the range of 3300-3700ms. The average length of Object is 3851.2ms, most of which fall in the range of 3100-4200ms, occasionally exceeding 4800ms.

When reaching 8 million, the average length of Map is 6004.2ms, most of which fall in the range of 5500-6500ms. The average length of Object is 9171ms, most of which fall in the range of 8500-9500ms, occasionally exceeding 10500ms.

When the number exceeds 10 million, the average Map duration is 7582ms, while Object will cause the browser to suspend animation very frequently, and the comparison ends.

Insert the number of times Map Object
100000 Up and down 50 ms Up and down 60 ms
1 million Up and down 590 ms Up and down 650 ms
5 million 3542.4 ms 3851.2 ms
8 million 6004.2 ms 9171ms

Conclusion: In the case of frequent insertion operations, Map has better performance than Object, and the time distribution is more convergent.

Query operation

var m = new Map(a)for(let i = 0; i<1000000; i++) {
    m.set('m'+i, i)
}
var now = performance.now()
for(let j = 0; j<1000000; j++) {
  m.get('m'+j)
}
console.log(performance.now() - now)

var o = {}
for(let i = 0; i<1000000; i++) {
    o['o'+i] = i
}
var now = performance.now()
for(let j = 0; j<1000000; j++) {
  o['o'+j]
}
console.log(performance.now() - now)
Copy the code
Number of queries Map Object
100000 24.6 ms 41.9 ms
500000 52.4 ms 170.5 ms
1 million 83.2 ms 354.6 ms
5 million 336.9 ms 2162.2 ms

Conclusion: In the case of frequent query operations, Map performs better than Object, and the time difference of 100,000 level is 2-4 times, and that of million level is about 4-6 times

Common operation

Initialize assignment

Initialize an assignment using a two-dimensional array, such as [[key0, value0], [key1, value1]…

var m = new Map([[123.'abc'], ['aaa'.true]])
console.log(m)
// output: {123 => "abc", "aaa" => true}
Copy the code

cloning

Clone a Map object from a Map object. As you can see from the following code, the key of the object data type does not affect the query even if the object content changes. Similarly, the value of the object data type is just a clone of the pointer to the object.

var o = {name: 'Jack'}
var o2 = {msg: 'hello'}
var m = new Map([['k', o2], ['a'.123]])
m.set(o, [1.2.3])
var m2 = new Map(m)
o2.msg = 'hi'
console.log(m)
// output: {"k" => {... }, "a" => 123, {... } => Array(3)}
console.log(m2)
// output: {"k" => {... }, "a" => 123, {... } => Array(3)}
console.log(m === m2)
// output: false
console.log(m.get('k') === m2.get('k'))
// output: true
console.log(m.get('k'))
// output: {msg: 'hi'}
m.delete('k')
m2.set('k'.'v')
console.log(m)
// output: {"a" => 123, {... } => Array(3)}
console.log(m2)
// output: {"k" => "v", "a" => 123, {... } => Array(3)}
o.name = 'David'
console.log(m.get(o))
// output: [1, 2, 3]
console.log(m2.get(o))
// output: [1, 2, 3]
Copy the code

merge

The merge of two maps cannot be passed in as a parameter when it is created. Instead, it needs to be converted into a two-dimensional array with the same key.

var m = new Map([['x'.'abc'], ['y'.233]])
var m2 = new Map([['x'.Awesome!], ['z'.'hhh']])
var m3= new Map(m, m2)
var m4 = new Map([...m, ...m2])
console.log(m3)
// output: {"x" => "abc", "y" => 233}
console.log(m4)
// output: {"x" => 666, "y" => 233, "z" => "hhh"}
Copy the code

WeakMap

Different from Map, the key in key-value pairs stored by a WeakMap object can only be the object data type.

An error is raised when you try to insert a key of a non-object data type.

Uncaught TypeError: Invalid value used as weak map key
    at WeakMap.set (<anonymous>)
    at <anonymous>:1:3
Copy the code

Difference between WeakMap and Map

There are two main differences between the two:

  • WeakMap’s key can only store objects, while Map can store any data type, no matter key or value
  • WeakMap stores an object that will be garbage collected if there are no other references. This is why WeakMap is called Weak, and it also means that WeakMap is not enumerable, so there is no size.

Try the following code in Chrome’s Developer Tools Console panel:

methods

Compared with Map, WeakMap has weak reference characteristics, resulting in only the following four methods:

  • set(key, value)Add key-value pairs
  • get(key)Returns the value associated with this key
  • delete(key)Delete key-value pairs equal to this key
  • has(value)Returns whether the value is included

Practical scenario

  • Operate on DOM and hold DOM nodes. Using WeakMap, DOM nodes can be deleted by other code logic, which can facilitate memory recovery and prevent memory leakage
  • Babel compiles the private properties of classes in ES6, as I did in my previous article in TypeScript Small situation objects

compatibility

Finally, take a look at browser compatibility.

Map

WeakMap

Basically, most modern browsers support Map and WeakMap, and most usage scenarios can be safely used.