preface
Recently, I was asked about the difference between ES6 Set and Map, and WeakSet and WeakMao data structure. I was a little confused and forgot?? It seems that knowledge needs to be reviewed frequently, so there is this article, PS: set and map are the two data structures that are always needed for front-end comparison, or they need to understand how to use them.
This article mainly refers to the ES6 introduction document, for the convenience of the next search, then recorded down, if there is a wrong place can refer to the original document.
Set
Similar to an array, but with unique values and no duplicate values.
let arr= [1.2.3.4.3.4]
Array.from(new Set(arr)); / / [1, 2, 3, 4]
Copy the code
The algorithm used to determine whether two values are different inside a Set is similar to the exact equality operator (===), the main difference being that NaN is equal to itself in the Set structure, whereas the exact equality operator considers NaN not equal to itself. The Set itself is a constructor used to generate the Set data structure.
define
The Set function can take an array (or an array-like object) as an argument for initialization.
// Define a set and structure
var s = new Set(a)var s1 = new Set([1.2.3.3])
Copy the code
let set = new Set(a); set.add({}); set.size/ / 1
set.add({});
set.size / / 2
Copy the code
Also, two objects in a Set are always unequal (multiple empty objects can be added to the Set structure). As you can see from the code above, two empty objects are treated as two values because they are not equal.
Properties and methods of a Set instance
Instances of the Set structure have the following properties
- Set. The prototype. The constructor: constructor, the default is Set function.
- Set.prototype.size: Returns the total number of members of a Set instance.
Instance methods of the Set structure fall into two broad categories: operation methods (which operate on arrays) and traversal methods (which traverse members in English).
- Add (value) : Adds a value and returns the Set structure itself.
- Delete (value) : deletes a value and returns a Boolean value indicating whether the deletion is successful.
- Has (value) : Returns a Boolean value indicating whether the value is a member of Set.
- Clear () : Clears all members with no return value.
Traversal operation:
- 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, with no return value. This function takes the key value, the key name, and the collection itself. In addition, the forEach method can have a second argument that represents the bound this object.
Note: The order in which a Set is traversed is the order in which it is inserted. This feature can be useful in situations such as using a Set to store a list of callback functions that can be called in the order in which they were added.
An instance of a Set structure is traversable by default, and its default traverser generator is its values method.
Set.prototype[Symbol.iterator] === Set.prototype.values
// true
Copy the code
This means that you can omit the values method and use for… Of loops through Set.
The map and filter methods for traversing arrays of Set structures can also be used with Set extension operators (…).
If you want to change the Set structure synchronously during traversal:
- Use the original
Set
Structure maps a new structure and then assigns to the original Set structure - using
Array.from
methods
/ / method
let set = new Set([1.2.3]);
set = new Set([...set].map(val= > val * 2));
// Set values are 2, 4, 6
/ / method 2
let set = new Set([1.2.3]);
set = new Set(Array.from(set, val= > val * 2));
// Set values are 2, 4, 6
Copy the code
WeakSet
WeakSet structure is similar to Set, which is also a collection of non-repeating values. But there are two differences between it and Set.
WeakSet and Set difference
WeakSet
A member of a can only be an object, not another type of valueWeakSet
Objects inA weak reference
, that is, the garbage collection mechanism does not consider WeakSet’s reference to the object, that is, if other objects no longer reference the object, the garbage collection mechanism will automatically recover the memory occupied by the object, regardless of the object still exists inWeakSet
. This characteristic means that it cannot be referencedWeakSet
Members of, thereforeWeakSet
It’s not traversable.
Common grammar
WeakSet is a constructor that creates a WeakSet data structure using the new command.
var ws = new WeakSet(a); ws.add(1)
// TypeError: Invalid value used in weak set
// Add an error because WeakSet can only place objects
Copy the code
As a constructor, A WeakSet can take an array or array-like object as a parameter, and all members of that array automatically become members of a WeakSet instance object. Not the array itself, which means that all the members of the array must be objects in order to define success.
var a = [[1.2], [3.4]].var ws = new WeakSet(a);// Define success
var b = [3.4];
var ws = new WeakSet(b);// Define failure
// Uncaught TypeError: Invalid value used in weak set(...)
Copy the code
WeakSet structure method
WeakSet. Prototype. The add (value) :
Add a new member to the WeakSet instance.WeakSet. Prototype. Delete (value) :
Clears the specified member of a WeakSet instance.WeakSet) prototype) from the (value) :
Returns a Boolean value indicating whether a value is in a WeakSet instance.
Note: WeakSet does not have size attribute, and WeakSet members are weak references, may disappear at any time, traversal mechanism cannot guarantee the existence of members, it is likely that just after traversal, members can not be taken. So there is no way to traverse WeakSet members.
WeakSet is useful for storing DOM nodes without worrying about memory leaks when they are removed from documents.
Map
The existence significance of Map structure
Because objects in Javascript only accept strings as key names, their use is very limited.
To solve this problem,ES6 provides Map data structures.
A Map is similar to an object, which is also a collection of key-value pairs. A Map object is also an ordered collection of key-value pairs. Because Map remembers the original insertion order of the keys, the Map object is traversed in the order in which it was inserted. This can solve the disorder of object key-value pairs. However, the scope of “keys” is not limited to strings; all types of values (including objects) can be used as keys. That is, the Object structure provides a string-value counterpart. The Map structure provides value-to-value correspondence, which is a perfect implementation of Hash structures. Map is more suitable for key-value pairs than Object.
var m = new Map(a);var o = {p: 'Hello World'};
m.set(o, 'content') // use o as a key of m
m.get(o) // "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false
Copy the code
A Map, as a constructor, can take an array of members representing key-value pairs.
var map = new Map([['name'.'Joe'],
['title'.'es6']]);// Map(2) {"name" => "Author", "title" => "Author"}
Copy the code
The Map constructor, which takes an array as an argument, actually executes the following code.
var items = [
['name'.'Joe'],
['title'.'es6']].var map = new Map(a); items.forEach(([key, value]) = > map.set(key, value));
Copy the code
True for Boolean and true for string are two different keys in Map. If the same key is assigned more than once, the subsequent value overrides the previous value. Reading a nonexistent key returns undefined
Note: Only references to the same object will be treated as the same key by the Map structure.
var map = new Map(a); map.set(['a'].Awesome!);
map.get(['a']) // undefined
Copy 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. Similarly, two instances of the same value are socially double key in the Map.
Conclusion:
Map
The key is actually bound to the memory address. As long as the memory address is different, it is treated 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. 2. If the Map’s key is a value of a simple data type (number, Boolean, string), the Map will treat the two values as one key as long as they are strictly equal. Both 0 and minus 0. Also, although NaN is not strictly equal to itself, it is treated as the same key in a Map.
Attributes and methods of the Map instance
attribute
-
Size property: Returns the total number of Map structure members.
-
Set (key, value) : Sets the key value corresponding to the key, and then the whole Map structure (so can use chain notation). If a key already exists, the key value is updated; otherwise, a new key value is generated.
-
Get (key): Reads the key corresponding to the key and returns undefined if it cannot be found.
-
Has (key): Returns a Boolean indicating whether a key is in the Map data structure.
-
Delete (key): deletes a key. The value is true if the key is deleted. If deletion fails, return false.
-
Clear (): method clears all members with no return value.
Traversal methods
Map natively provides three traverser generating functions and one traversal method.
- Keys () : returns a traverser for key names.
- Values () : Iterator that returns key values.
- Entries () : Returns a traverser for all members.
- ForEach () : traverses all Map members.
Note in particular that the Map traversal order is the insertion order.
The default iterator interface of the Map structure (the symbol. iterator property) is the entries method.
map[Symbol.iterator] === map.entries
// true
Copy the code
Transformation of Map data structures and other data structures
Map to array
let myMap = new Map().set(true.7).set({foo: 3},'abc']);
Copy the code
- The easiest way to do this is to extend the operator (
.
); use[...myMap]
- Array. The from conversion;
Array.from(myMap)
Array to Map
We turn the array into a Map by passing it into the Map constructor.
new Map([[true.7], [{foo: 3},'abc']]])
// Map {true => 7, Object {foo: 3} => ['abc']}
Copy the code
Map to object
If all Map keys are strings, it can be turned into objects.
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [k,v] of strMap) {
obj[k] = v;
}
return obj;
}
let myMap = new Map().set('yes'.true).set('no'.false);
strMapToObj(myMap)
// { yes: true, no: false }
Copy the code
Object to Map
function objToStrMap(obj) {
let strMap = new Map(a);for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
}
objToStrMap({yes: true.no: false})
// [ [ 'yes', true ], [ 'no', false ] ]
Copy the code
The Map to Json
There are two different cases of Map conversion to JSON. In one case, Map keys are all strings, and you can choose to convert to object JSON.
function strMapToJson(strMap) {
return JSON.stringify(strMapToObj(strMap));
}
let myMap = new Map().set('yes'.true).set('no'.false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'
Copy the code
Alternatively, if the Map has a non-string key name, you can choose to convert it to an array JSON.
function mapToArrayJson(map) {
return JSON.stringify([...map]);
}
let myMap = new Map().set(true.7).set({foo: 3},'abc']);
mapToArrayJson(myMap)
// '[[true,7],[{"foo":3},["abc"]]]'
Copy the code
Json string is converted to Map
JSON to Map. Normally, all key names are strings.
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes":true,"no":false}')
// Map {'yes' => true, 'no' => false}
Copy the code
However, there is a special case where the entire JSON is an array, and each array member itself is an array with two members. In this case, it can be converted into a Map. This is often the inverse of an array to JSON.
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}
Copy the code
WeakMap
The structure of WeakMap is similar to that of Map structure section, the only difference is that WeakMap only accepts objects as key names (except null) and does not accept other types of values as key names, and the object that the key name points to is not included in the garbage collection mechanism.
WeakMap is designed so that the key name is a weak reference to the object (which is not taken into account by the garbage collection mechanism), so its corresponding object may be automatically reclaimed.
When the object is reclaimed, WeakMap automatically removes the corresponding key-value pair. A typical application is a WeakMap structure corresponding to DOM elements. When a DOM element is cleared, its corresponding WeakMap record will be automatically removed. Basically, the special use of WeakMap is that the object to which its key corresponds may disappear in the future. The WeakMap structure helps prevent memory leaks
WeakMap
withMap
There are two main differences in the API
- One is that there is no traversal operation (i.e
key()
, v,alues()
andentries()
Method), neithersize
Properties; - Second, it cannot be cleared, that is, it is not supported
clear
Methods. This is related to the fact that the key of WeakMap is not included in the reference and is ignored by the garbage collection mechanism. Therefore, WeakMap has only four methods available:get()
,set()
,has()
,delete()
.
Another use of WeakMap is to deploy private properties.
let _counter = new WeakMap(a);let _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) (); }}}let c = new Countdown(2.() = > console.log('DONE'));
c.dec() // DONE
Copy the code
In the code above, the two internal attributes of the Countdown class, _counter and _action, are weak references to the instance, so if the instance is deleted, they disappear without causing a memory leak.