ES6: Map structure

1. Create a map

It is similar to an object and is also a collection of key-value pairs, but the scope of the "key" is not limited to strings, and various types of values ​​(including objects) can be used as keys. In other words, the Object structure provides a "string-value" correspondence, and the Map structure provides a "value-value" correspondence, which is a more complete implementation of the Hash structure. If you need a "key-value pair" data structure, Map is more suitable than Object.

const m = new Map();
const o = {
    
    p: 'Hello World'};
 
m.set(o, 'content')
m.get(o) // "content"
 
m.has(o) // true
m.delete(o) // true
m.has(o) // false

The above code uses the set method of the Map structure to treat the object o as a key of m, then uses the get method to read the key, and then uses the delete method to delete the key.

2. Initialize Map

The above example shows how to add members to Map. As a constructor, Map can also accept an array as a parameter. The members of the array are arrays representing key-value pairs.

const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);
 
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
console.log(map)  // {"name" => "张三", "title" => "Author"}

In fact, not just arrays, but any data structure that has an Iterator interface and each member is an array of two elements (see the chapter "Iterator Object" for details) can be used as a parameter of the Map constructor. That is to say, both Set and Map can be used to generate new Map.

const set = new Set([
  ['foo', 1],
  ['bar', 2]
]);
console.log(set) // Set(2) {Array(2), Array(2)}
// 使用 set 
const m1 = new Map(set);
console.log(m1) //Map(2) {"foo" => 1, "bar" => 2} 
m1.get('foo') // 1
 
const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
m3.get('baz') // 3

Returns undefined if an unknown key is read.

new Map().get('asfddfsasadf')
// undefined

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

const map = new Map();
 
map.set(['a'], 555);
map.get(['a']) // undefined

The set and get methods of the above code appear to be for the same key, but in fact these are two different array instances with different memory addresses, so the get method cannot read the key and returns undefined.

Similarly, two instances of the same value are regarded as two keys in the Map structure.

const map = new Map();
 
const k1 = ['a'];
const k2 = ['a'];
 
map
.set(k1, 111)
.set(k2, 222);
 
map.get(k1) // 111
map.get(k2) // 222

In the above code, the values ​​of variables k1 and k2 are the same, but they are regarded as two keys in the Map structure

It can be seen from the above that the key of Map is actually bound to the memory address. As long as the memory address is different, it is regarded as two keys. This solves the problem of attribute collisions with the same name. When we expand other people's libraries, if we use objects as key names, we don't have to worry about our attributes having the same name as the original author's attributes.

If the key of the Map is a value of a simple type (number, string, Boolean), then as long as two values ​​are strictly equal, the Map treats it as a key, such as 0 and -0 are a key, Boolean true and character The string true is 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) // 123

3. Properties of Map

The attribute size attribute of the instance
returns the total number of members of the Map structure.

const map = new Map();
map.set('foo', true);
map.set('bar', false);
 
map.size // 2

4. Map method

4.1 Map.prototype.set(key, value)

The set method sets the key value corresponding to the key name key to value, and then returns the entire Map structure. If the key already has a value, the key value will be updated, otherwise the key will be newly generated.

const m = new Map();
 
m.set('edition', 6)        // 键是字符串
m.set(262, 'standard')     // 键是数值
m.set(undefined, 'nah')    // 键是 undefined
set方法返回的是当前的Map对象,因此可以采用链式写法。

let map = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');

4.2 Map.prototype.get(key)

get方法读取key对应的键值,如果找不到key,返回undefined

const m = new Map();
 
const hello = function() {
    
    console.log('hello');};
m.set(hello, 'Hello ES6!') // 键是函数
 
m.get(hello)  // Hello ES6!

4.3 Map.prototype.has(key)

The has method returns a Boolean value indicating whether a key is in the current Map object.

const m = new Map();
 
m.set('edition', 6);
m.set(262, 'standard');
m.set(undefined, 'nah');
 
m.has('edition')     // true
m.has('years')       // false
m.has(262)           // true
m.has(undefined)     // true

4.4 Map.prototype.delete(key)

The delete method deletes a key and returns true. Returns false if deletion failed.

const m = new Map();
m.set(undefined, 'nah');
m.has(undefined)     // true
 
m.delete(undefined)
m.has(undefined)       // false

4.5 Map.prototype.clear()

The clear method clears all members and has no return value.

let map = new Map();
map.set('foo', true);
map.set('bar', false);
 
map.size // 2
map.clear()
map.size // 0

Traversal Methods
The Map structure natively provides three traverser generation functions and one traverse method.

  1. Map.prototype.keys(): returns a traverser of key names.
  2. Map.prototype.values(): returns a iterator for key values.
  3. Map.prototype.entries(): returns a traverser for all members.
  4. Map.prototype.forEach(): traverse all members of the Map.
    It is important to note that the traversal order of the Map is the insertion order.
const map = new Map([
  ['F', 'no'],
  ['T',  'yes'],
]);
 
for (let key of map.keys()) {
    
    
  console.log(key);
}
// "F"
// "T"
 
for (let value of map.values()) {
    
    
  console.log(value);
}
// "no"
// "yes"
 
for (let item of map.entries()) {
    
    
  console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"
 
// 或者
for (let [key, value] of map.entries()) {
    
    
  console.log(key, value);
}
// "F" "no"
// "T" "yes"
 
// 等同于使用map.entries()
for (let [key, value] of map) {
    
    
  console.log(key, value);
}
// "F" "no"
// "T" "yes"

Represents the default traverser interface (Symbol.iterator property) of the Map structure, which is the entries method.

map[Symbol.iterator] === map.entries
// true

In addition, Map also has a forEach method, which is similar to the forEach method of an array and can also be traversed.

map.forEach(function(value, key, map) {
    
    
  console.log("Key: %s, Value: %s", key, value);
});
 
const map = new Map([
['F', 'no'],
['T',  'yes'],
]);
map.forEach(function(value, key, map) {
    
    
console.log("Key: %s, Value: %s", key, value);
});
// Key: F, Value: no
// Key: T, Value: yes
forEach方法还可以接受第二个参数,用来绑定this

const reporter = {
    
    
  report: function(key, value) {
    
    
    console.log("Key: %s, Value: %s", key, value);
  }
};
 
map.forEach(function(value, key, map) {
    
    
  this.report(key, value);
}, reporter);

In the above code, the this of the callback function of the forEach method points to the reporter.

5. Interconversion with other data structures

5.1 Convert Map to Array

As mentioned earlier, the most convenient way to convert a Map into an array is to use the spread operator (…).

onst map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);
 
[...map.keys()]
// [1, 2, 3]
 
[...map.values()]
// ['one', 'two', 'three']
 
[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]
 
[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]
 
const myMap = new Map()
  .set(true, 7)
  .set({
    
    foo: 3}, ['abc']);
 
 console.log(myMap)  // Map(2) {true => 7, {foo: 3} => ['abc']}
 
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]

5.2 Convert array to Map

The array can be converted into a Map by passing it into the Map constructor.

new Map([
  [true, 7],
  [{
    
    foo: 3}, ['abc']]
])
// Map {
    
    
//   true => 7,
//   Object {foo: 3} => ['abc']
// }

5.3 Convert Map to Object

If all Map keys are strings, it can be converted losslessly to objects.

function strMapToObj(strMap) {
    
    
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    
    
    obj[k] = v;
  }
  return obj;
}
 
const myMap = new Map()
  .set('yes', true)
  .set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }

If there is a non-string key name, the key name will be converted into a string and then used as the key name of the object.

5.4 Object to Map

Objects can be converted to Map through Object.entries().

let obj = {
    
    "a":1, "b":2};
let map = new Map(Object.entries(obj));
此外,也可以自己实现一个转换函数。

function objToStrMap(obj) {
    
    
  let strMap = new Map();
  for (let k of Object.keys(obj)) {
    
    
    strMap.set(k, obj[k]);
  }
  return strMap;
}
 
objToStrMap({
    
    yes: true, no: false})
// Map {"yes" => true, "no" => false}

5.5 Convert Map to JSON

Converting Map to JSON requires distinguishing between two situations.

In one case, the keys of the Map are all strings, and you can choose to convert them to JSON objects.

function strMapToJson(strMap) {
    
    
  return JSON.stringify(strMapToObj(strMap));
}
 
let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'

In another case, if the key name of the Map has a non-string 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"]]]'

5.6 Convert JSON to Map

Convert JSON to Map. Normally, all keys are strings.

function jsonToStrMap(jsonStr) {
    
    
  return objToStrMap(JSON.parse(jsonStr));
}
 
jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}

However, there is a special case where the entire JSON is an array, and each array member itself is an array with two members. At this time, it can be converted into a Map in one-to-one correspondence. This is often the inverse of Map to Array JSON.

function jsonToMap(jsonStr) {
    
    
  return new Map(JSON.parse(jsonStr));
}
 
jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}

6. Use the method of array to realize the traversal and filtering of Map (Map itself has no map and filter methods)

The map method and filter method of the array can realize the traversal and filtering of the Map (Map itself has no map and filter methods).

const map0 = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');
 
const map1 = new Map(
  [...map0].filter(([k, v]) => k < 3)
);
// 产生 Map 结构 {1 => 'a', 2 => 'b'}
 
const map2 = new Map(
  [...map0].map(([k, v]) => [k * 2, '_' + v])
    );
// 产生 Map 结构 {2 => '_a', 4 => '_b', 6 => '_c'}

Guess you like

Origin blog.csdn.net/DZQ1223/article/details/131328602