Geek-James/Blog

2.ES6详解-Map Set Symbol

Geek-James opened this issue · 1 comments

特性

ES6提供了”值-值“对的数据结构,键名不仅可以是字符串,也可以是对象。它是一个更完善的Hash结构。

1.键值对,键可以是对象

    const map1 = new Map();
    const objkey = {p1:'v1'};
    map1.set(objkey,'hello');
    console.log(map1.get(objkey)); // hello
    

2.Map可以接受数组作为参数,数组成员还是一个数组,其中有两个元素,一个表示键一个表示值。

    const map2 = new Map([['name','james'],['age',18],['profession','software']]);
    console.log(map2.get('name')); // james
    console.log(map2.get('age'));// 18
    

操作

1.size 获取map的大小长度

    const map2 = new Map([['name','james'],['age',18],['profession','software']]);
    console.log(map2.size); // 3

2.设置键值对,键可以是各种类型,包括undefined,function等

  const map4 = new Map();
    map4.set('k1',5);
    map4.set(222,'哈哈哈');
    map4.set(undefined,'ggggg');
    const fun = function(){
        console.log('hello 我是方法');
    }
    map4.set(fun,'fun');
    console.log('map4 size :%s',map4.size);  // 4
    console.log('undefined value :%s',map4.get(undefined)); //ggggg
    console.log('fun value:%s',map4.get(fun)); //fun

3.也可对set进行链式调用。

map4.set('k2', 2).set('k3', 4).set('k4', 5)

4.get 获取键对应的值

    const map4 = new Map();
    map4.set('k1',5);
    
  1. has 判断键是否存在
    const map5 = new Map();
    map5.set(undefined,4);
    console.log('map undefined:%s',map5.has(undefined)); //true
    console.log('map k1:%s',map5.has('k1'));// false

6.delete 删除键值对

    const map5 = new Map();
    map5.set(undefined,4);
    console.log('map undefined:%s',map5.has(undefined)); //true
    map5.delete(undefined);
    console.log('map undefined:%s',map5.has(undefined)); //false

7.clear 删除map中所有的键值对

    const map5 = new Map();
    map5.set('a','ad').set('b',111).set(3,333).set(fun,'demo');
    console.log(map5.size); // 4
    map5.clear();
    console.log(map5.size); // 0
  • 注意点:

如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键,比如0和-0就是一个键,布尔值true和字符串true则是两个不同的键。另外,undefined和null也是两个不同的键。虽然NaN不严格相等于自身,但 Map 将其视为同一个键,如下代码所示.

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

遍历

1.keys() 遍历map的所有key

    for (let key of map5.keys()) {
        console.log(key);
    }

2.values() 遍历map的所有value

 for (let key of map5.values()) {
        console.log(key);
    }

3.entries() 遍历map的所有键值对

方法一:

 for (let item of map5.entries()) {
        console.log("key:%s, value:%s",item[0],item[1]);
    }

方法二:

    for(let [key,value] of map5.entries()) {
        console.log("key:%s, value:%s",key,value);
    }

4.forEach 遍历map所有的键值对

    map5.forEach(function(value,key,map){
        console.log("key:%s, value:%s, map:%s",key,value,map.size);
    }); 

forEach知识拓展:
forEach有第二个参数,可以用来绑定this。
这样有个好处,map的存储的数据和业务处理对象可以分离,业务处理对象可以尽可能的按职责分割的明确符合SRP原则。

   const output = {
        log:function(key,value){
            console.log("key:%s,Value:%s",key,value);
        },
        say:function(){
            console.log("来打我呀");
        }
    };

    map5.forEach(function(key,value){
        this.log(key,value);
        this.say();
    },output);

和其他结构的互转

1.Map To Array
使用扩展运算符(...) 可将map内的元素都展开为数组

    console.log(...map5);
    
    (2) ["a", "ad"]0: "a"1: "ad"length: 2__proto__: Array(0) (2) ["b", 111] (2) [3, 333] (2) [ƒ, "demo"]
    
    let arr = [...map5];
    console.log(arr);
    [...map5.keys()];
    [...map5.values()];
    [...map5.entries()];
    
   (4) [Array(2), Array(2), Array(2), Array(2)]
    0: (2) ["a", "ad"]
    1: (2) ["b", 111]
    2: (2) [3, 333]
    3: (2) [ƒ, "demo"]
    length: 4
    __proto__: Array(0)

结合数组的map方法、filter方法,可以实现 Map 的遍历和过滤(Map 本身没有map和filter方法)。

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"}

2.Array To Map
使用数组来构造一个map

    const map6 = new Map([
        ['name','james'],
        ['age',26]
    ])

    console.log(map6);
    
    Map(2) {"name" => "james", "age" => 26}
    

3.Map To Object

写一个转换函数,遍历map的所有元素,将元素的键和值作为对象属性名和值写入Object中。

function mapToObject(map) {
        // 创建一个空对象
        let obj = {};
        for (let [k,v] of map) {
            obj[k] = v; 
        }
        return obj;
    }
    console.log(mapToObject(map6));
    
   // {name: "james", age: 26}

4.Object To Map

同理,再写一个转换函数遍历Object,将属性名和值作为键值对写入Map。

function objectToMap(obj) {
        let map = new Map();
        for (let [k,v] of Object.entries(obj)){
            map.set(k,v);
        }
        return map;
    }
    let objs = mapToObject(map6);
    console.log(objectToMap(objs));
    // Map(2) {"name" => "james", "age" => 26}

注意点:

object 不能实现 for of 迭代循环,会报'x' is not iterable的TypeError.

这个值作为 for…of 的表达式右值,或者作为一个函数的参数,如 Promise.all 或者 TypedArray.from, 不是一个 可迭代对象. 一个可迭代对象可以是一个内置可迭代类型,如Array, String 或 Map, 一个 generator 生成结果, 或者一个实现了可迭代协议的对象.

方案一:

做为替代你必须使用 Object.keys

 function objectToMap(obj) {
        let map = new Map();
        for (let k of Object.keys(obj)){
            map.set(k,obj[k]);
        }
        return map;
    }

或 Object.entries 来迭代对象的属性或属性值.

function objectToMap(obj) {
        let map = new Map();
        for (let [k,v] of Object.entries(obj)){
            map.set(k,v);
        }
        return map;
    }

5.set To map

将创建好的set在创建map的构造函数时,直接传入

    const set = new Set([
        ['foo',1],
        ['bar',2]
    ]);
    const map9 = new Map(set);
    console.log(map9);
    // Map(2) {"foo" => 1, "bar" => 2}

6.map To set

遍历map中的键值,然后add到set中

    function mapToSet(map) {
        let set = new Set();
        for (let [k,v] of map) {
            set.add([k,v]);
        }
        return set;
    }
    // Set(2) {Array(2), Array(2)}

7.Map 转为 JSON
Map 转为 JSON 要区分两种情况。一种情况是,Map 的键名都是字符串,这时可以选择转为对象 JSON。