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
size
Read-only property that returns the number of key-value pairs
methods
set(key, value)
Add key-value pairsget(key)
Returns the value associated with this keyclear()
Remove all key-value pairsdelete(key)
Delete key-value pairs equal to this keyhas(value)
Returns whether the value is includedentries()
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 formforEach(callbackFn, thisArg)
Callback is executed with the key and value of each key-value pair as the first and second arguments, respectively, in insertion orderkeys()
Returns an iterator containing all the keys in the Map in insertion ordervalues()
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 pairsget(key)
Returns the value associated with this keydelete(key)
Delete key-value pairs equal to this keyhas(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.