ES6-Set集合与Map集合

239 阅读4分钟

Set

  • 新增的一种数据结构类型,它是一个构造函数,我们先创建一个看看是个什么东西。

    const set = new Set();
    console.log(set);
    

                      

  • 下面我们就介绍几个原型上常用的方法,来了解一下Set到底是怎么样的。                              1. add(value),在Set结构末尾添加一个元素,并且返回Set结构(可以链式调用)。我们发现添加的重复元素在Set中自动被过滤,得出Set的成员具有唯一性。
  •   const set = new Set();
      set.add(3)
         .add(6)
         .add(3)
         .add(3);
      console.log(set); // -> Set(2) {3, 6}
      
      // 也可以构造函数初始化参数,但是参数的形式只能是具备iterator接口的数据结构
      const set1 = new Set([3, 6, 6, 6, 6, 6]);
      console.log(set1); // -> Set(2) {3, 6}
      
      // 判断一些特殊的值
      const test = new Set([undefined, undefined, null, null, 3, '3', NaN, NaN]);
      console.log(test);
      // 结果 ->  
      Set(5) {undefined, null, 3, "3", NaN}
        [[Entries]]
          0: undefined
          1: null
          2: 3
          3: "3"
          4: NaN  // -> NaN === NaN
        size: (...)
        __proto__: Set
    

       2. delete(),删除Set结构中的元素,返回值是一个布尔值。size,Set结构的长度

     (相当于数组的length)

  •   let x = {id: 1},
          y = {id: 2};
      const set = new Set();
      set.add(x)
         .add(y)
         .add(x); // 这里我们拿的对象的引用,所以就相当于同一个对象
      console.log(set); // -> 左图
      console.log(set.size); // -> 2
      set.delete(y);
      console.log(set); // -> 右图
    

                                          

       3. clear(),清空Set结构中的所有值。

  •   const set = new Set([1, 2, 3, 4, 5]);
      console.log(set); // -> Set(5) {1, 2, 3, 4, 5}
      set.clear();
      console.log(set); // -> Set(0) {}
    

       4. has(value),判断当前Set结合是否存在该值,返回一个布尔值。

  •   const set = new Set(['zhangsan', 'lisi', 'wangwu']);
      console.log(set.has('zhangsan')); // -> true
      console.log(set.has('zhaoliu')); // -> false
    

       5. keys() / values() / entries(),返回一个迭代器对象。我们发现key和value相同。

  •   const set = new Set(['a', 'b', 'c']);
      for(let item of set.keys()){
        console.log(item); // -> a  b  c
      }
      // set结构中不存在key
      for(let item of set.values()){
        console.log(item); // -> a  b  c
      }
      for(let item of set.entries()){
        console.log(item); // -> ['a', 'a'] ['b', 'b'] ['c', 'c']
      }
    

       6. forEach(),Set本身没有key,所以forEach方法中的key被设置为了元素本身。

  •   const set = new Set([1, 2, 3]);
      set.forEach((item, key) => {
        console.log(item, key); // ->  1 1  2 2  3 3
      })
    
  • 最简单的数组去重

    let arr = [1, 2, 2, 1, 3, 3, 3];
    let set = new Set(arr);
    arr = [...set];
    console.log(arr); // -> [1, 2, 3]
    
  • 交集、并集、差集

    let a = new Set([1, 2, 3]),
        b = new Set([2, 3, 4]);
    
    let intersect = new Set([...a].filter(item => b.has(item)));
    console.log(intersect); // -> Set(2) {2, 3}
    
    let union = new Set([...a, ...b]);
    console.log(union); // -> Set(4) {1, 2, 3, 4}
    
    let differenceA = new Set([...a].filter(item => !b.has(item)));
    console.log(differenceA); // -> Set(1) {1}
    
    let differenceB = new Set([...b].filter(item => !a.has(item)));
    console.log(differenceB); // -> Set(1) {4}
    

Map

  • 如果说Set像数组,那Map就更像对象,他比对象更强大,对象的key只支持字符串,而Map的key支持所有的数据类型,就可以实现键与值一一对应的关系。Map集合的原型上多了两个方法set()get(), 没有了add() 方法。

    // 对象key的问题
    let a = {id: 1},
        b = {id: 2},
        c = {};
    c[a] = 'foo';
    c[b] = 'bar';
    
    console.log(c[a]); // -> bar
    console.log(c[b]); // -> bar
    // 因为对象的key只支持字符串,所以通过调用toString方法, 他们两个的key都是'[object Object]'
    
    let map = new Map();
    console.log(map);
    map.set(a, 'foo');
    map.set(b, 'bar');
    console.log(map); // -> Map(2) {{…} => "foo", {…} => "bar"}
    // 获取值 要用 get方法
    console.log(map.get(a)); // -> foo
    console.log(map.get(b)); // -> bar
    

                            

  • 初始化参数不仅要满足是具备iterator接口的数据结构,并且里面的每一个元素都要是一个双元的数组结构,数组中第一个是键名,第二个是键值。

    const m = new Map([
      ['name', 'zhangsan'], 
      ['age', 22]
    ]);
    
    console.log(m); // -> Map(2) {"name" => "zhangsan", "age" => 22}
    
  • 特殊值覆盖的问题

    const map = new Map();
    
    map.set(-0, 123);
    console.log(map.get(+0)); // -> 123
    console.log(+0 === -0); // -> true
    Object.is(+0, -0); // -> false
    
    map.set(true, 1);
    map.set('true', 2);
    console.log(map.get(true)); // -> 1
    
    map.set(undefined, 1);
    map.set(null, 2);
    console.log(map.get(undefined)); // -> 1
    
    // 上面的都符合的是 === 规则,这里的NaN走的是Object.is()
    map.set(NaN, 3);
    console.log(map.get(NaN)); // -> 3
    console.log(NaN === NaN); // -> false
    console.log(Object.is(NaN, NaN)); // -> true
    
  • Map转化

    // Map -> 数组
    let map = new Map();
    map.set(true, 1);
    map.set({a: 1}, ['f', 'o', 'o']);
    let res = [...map];
    
    // 数组 -> Map
    let map = new Map([
      [true, 1],
      [{a: 1}, ['f', 'o', 'o']]
    ])
    
    // Map -> 对象
    let map = new Map();
    Map.set('name', 'rich brian');
    // 有一个条件 Map 成员的 key 必须为字符串
    function strMapToObj (strMap) {
      let obj = Object.create(null);
    
      for(let [key, val] of strMap.entries()){
        obj[key] = val;
      }
    
      return obj;
    }
    strMapToObj(map);
    
    // 对象 -> Map
    let obj = {
      a: 33,
      b: false
    }
    
    function objToMap (obj) {
      let map = new Map();
    
      for(let key of Object.keys(obj)) {
        map.set(key, obj[key]);
      }
      
      return map;
    }
    objToMap(obj);
    

总结

       Set集合可以用来过滤数组中重复的元素(成员的唯一性),只能通过has()方法来检测值是否存在,或是通过遍历来处理每个值(因为Set没有key)。Map集合可以看做是比Object更加强大的对象。