ES6学习总结之Set和Map的使用

Set数据结构

一、Set简介

  • Set中成员的值都是唯一的,没有重复的值

  • 向Set中添加成员时,不会发生类型转换

  • 向Set中添加的对象总是不相等

二、常用的属性和方法

属性:

  • size:返回set实例的成员总数

方法:

  • add():添加某个值,返回set本身

  • delete():删除某个值,返回一个布尔值,判断删除是否成功

  • has():返回一个布尔值,表示该值是否为set成员

  • clear():清除所有成员,没有返回值

  • keys():返回键名的遍历器

  • values():返回键值的遍历器

  • entries():返回键值对的遍历器

  • forEach():使用回调函数遍历每个成员

三、实例剖析

1、Set的基本用法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>数组去重</title>
    </head>
    <body>
        <script type="text/javascript">
            const set=new Set();    //创建set数据结构
            [1,1,2,3,4,5].forEach(x=>{
                set.add(x);
            })
            console.log(set);    //Set(5){1,2,3,4,5}
            for(let i of set){
                console.log(i);
            }
        </script>
    </body>
</html>

 可以看到向Set添加成员时,不会添加重复的值

2、数组作为参数传入到Set结构中

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <script type="text/javascript">
        //const set=new Set([1,2,3]);
        //console.log(...set);//Set(3){1,2,3},使用扩展运算符
            const set=new Set(document.querySelectorAll('div'));
            console.log(set.size);//5 size返回set实例的成员总数
            //如上代码相当于
            const item=new Set();
            document.querySelectorAll('div').forEach(x=>{
                item.add(x);
            })
            console.log(item);//Set(5) {div, div, div, div, div}
            console.log(item.size);//5
        </script>
    </body>
</html>

3、Set中添加的值不会发生类型转换

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>向set中添加成员时,不会发生类型转换</title>
    </head>
    <body>
        <script type="text/javascript">
            let mySet=new Set();
            mySet.add(5);
            mySet.add('5');
            console.log(mySet);//Set(2) {5, '5'}
            let set=new Set();
            let a=NaN;
            let b=NaN;
            set.add(a);
            set.add(b);
            console.log(set);//Set(1) {NaN}
        </script>
    </body>
</html>

向 Set 加入值的时候,不会发生类型转换,所以5"5"是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为NaN不等于自身。

4、Set中添加的对象总是不相等的

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>向set中添加的对象总是不想等</title>
    </head>
    <body>
        <script type="text/javascript">
            let set=new Set();
            set.add({});//向set中添加一个空对象
            console.log(set.size);//1
            set.add({});//向set中添加另一个空对象
            console.log(set.size);//2
        </script>
    </body>
</html>

由于两个空对象不相等,所以它们被视为两个值

5、Array.from()方法

Array.from()可以将set结构转为数组,这就提供了去除数组重复成员的另一种方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Array.from()方法</title>
    </head>
    <body>
        <script type="text/javascript">
            const items=new Set([1,2,3,4,5]);
            console.log(items);//Set(5) {1, 2, 3, 4, 5}
            const array=Array.from(items);
            console.log(array);//(5) [1, 2, 3, 4, 5]//Array.from()方法实现数组去重
            function dedupe(arr){
                return Array.from(new Set(arr))
            }
            console.log(dedupe([1,1,2,3]));//(3) [1, 2, 3]
        </script>
    </body>
</html>

四.Set的应用

1、数组去重

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>数组去重</title>
    </head>
    <body>
        <script type="text/javascript">
            let set=new Set(['red','blue','green']);
            let arr=[...set];
            console.log(arr);//(3) ['red', 'blue', 'green']//数组去重
            let arrs=[1,1,3,3,4,5,6];
            let unique=[...new Set(arrs)];
            console.log(unique);//(5) [1, 3, 4, 5, 6]
        </script>
    </body>
</html>

2、间接使用数组的方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>间接使用数组的方法</title>
    </head>
    <body>
        <script type="text/javascript">
            let set=new Set([1,2,3,4,5]);
            set=new Set([...set].map(x=>x*2));//使用数组的map方法
            console.log(set);//Set(5) {2, 4, 6, 8, 10}
            let mySet=new Set([1,2,3,4,5]);
            mySet=new Set([...mySet].filter(x=>x%2==0));//使用数组的filter方法
            console.log(mySet);//Set(2) {2, 4}
        </script>
    </body>
</html>

3、实现并集,交集,差集

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>实现并集,交集,差集</title>
    </head>
    <body>
        <script type="text/javascript">
            let a=new Set([1,2,3]);
            let b=new Set([4,3,2]);
            //并集
            let union=new Set([...a, ...b]);
            console.log(union);//Set(4) {1, 2, 3, 4}
            //交集
            let intersect=new Set([...a].filter(x=>b.has(x)));
            console.log(intersect);//Set(2) {2, 3}
            //差集
            let difference=new Set([...a].filter(x=>!b.has(x)));
            console.log(difference);//Set(1) {1}
        </script>
    </body>
</html>

4、同步改变原来的 Set 结构

如果想在遍历操作中,同步改变原来的 Set 结构,目前没有直接的方法,但有两种变通方法。一种是利用原 Set 结构映射出一个新的结构,然后赋值给原来的 Set 结构;另一种是利用Array.from方法。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>同步改变原来的 Set 结构</title>
    </head>
    <body>
        <script type="text/javascript">
            //方法一
            let set=new Set([1,2,3]);
            set=new Set([...set].map(val=>val*2));
            console.log(set);//2,4,6
            //方法二
            let mySet=new Set([1,2,3]);
            mySet=new Set(Array.from(mySet,val=>val*2));
            console.log(mySet);//2,4,6
        </script>
    </body>
</html>

五、Set实例属性和方法

1、size属性

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>set中的size属性</title>
    </head>
    <body>
        <script type="text/javascript">
            const set=new Set();
            //向set中添加成员
            set.add(1);
            set.add(2);
            set.add(3);
            //链式方法
            set.add(4).add(5).add(6);
            console.log(set.size);//6
        </script>
    </body>
</html>

2、操作方法add()、delete()、has()、clear()

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>set中的操作方法add()、delete()、has()、clear()</title>
    </head>
    <body>
        <script type="text/javascript">
            const set=new Set();
            //向set中添加成员
            set.add(1);
            set.add(2);
            set.add(3);
            //链式方法
            set.add(4).add(5).add(6);
            console.log(set.size);//6
            console.log(set.has(1));//true
            set.delete(1);
            console.log(set.has(1));//false
            set.clear();//清空全部set成员
            console.log(set.size);//0
        </script>
    </body>
</html>

3、遍历方法keys()、values()、entries()、forEach()

注意:Set的遍历顺序就是插入顺序,由于set没有键名,只有键值(或者说键名和键值是同一个值),所以keys()和values()方法的结果完全一致

<!DOCTYPE html>
<html>
    <head>
    <meta charset="UTF-8">
    <title>set中的遍历方法keys(),values(),entries(),forEach()</title>
  </head> 
  <body>
    <script type="text/javascript"> let set=new Set(['red','blue','green']); //遍历全部的key
       for(let key of set.keys()){
          console.log(key);
/* red                    
                      blue                                        
                      green*/
} //遍历全部的value for(let value of set.values()){ console.log(value);//red,blue,green } //遍历全部的key和value for(let item of set.entries()){ console.log(item);
                    
/* (2) ['red', 'red']                   
                     (2) ['blue', 'blue']                                           
                     (2) ['green', 'green']*/
       } 
       set.forEach((value,key)
=>{
          console.log(key
+':'+value);
                        /* red:red
                         blue:blue                                          
                         green:green
*/
       }) 
    </script>
  </body>
</html>

Map数据结构

一、Map简介

es6中的Map很大程度上和set相似,但是Map是以键值对的形式存储数据的

二、常用的属性和方法

属性:

  • size:返回Map结构的成员总数

方法:

  • set(key,value):设置键名key对应的键值value,然后返回整个map结构,如果key已经有值,则键值会被更新,否则就新生成该键

  • get(key):读取key对应的键值,如果找不到key,则返回undefined

  • has(key):返回一个布尔值,表示某个键是否在当前Map对象中

  • delete(key):删除某个key,返回true,如果删除失败,返回false

  • clear():清除所有成员,没有返回值

  • keys():返回键名的遍历器

  • values():返回键值的遍历器

  • entries():返回键值对的遍历器

  • forEach():遍历map的所有成员

三、实例剖析

1、size属性

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>map中的size属性</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map();
            map.set('foo',true);
            map.set('bar',false);
            console.log(map.size);//2
        </script>
    </body>
</html>

2、set(key,value)方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>map中的set()方法</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map();
            map.set('1','a');//键是字符串
            map.set(2,'b');//键是数值
            map.set(undefined,'3');//键是undefined
            console.log(map);//Map(3) {'1' => 'a', 2 => 'b', undefined => '3'}
            const myMap=new Map();
            //链式写法
            myMap.set(1,'a').set(2,'b').set(3,'c');
            console.log(myMap);//Map(3) {1 => 'a', 2 => 'b', 3 => 'c'}
        </script>
    </body>
</html>

3、get(key)方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>map中的get()方法</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map();
            const hello=function(){
                console.log('你好');
            }
            map.set(hello,'es6');//键是函数
            console.log(map.get(hello));//es6
        </script>
    </body>
</html>

4、has(key)方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>map中的has()方法</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map();
            //链式写法
            map.set('a',1).set('b',2).set('c',3);//向map中添加成员
            console.log(map.has('a'));//true
            console.log(map.has('b'));//true
            console.log(map.has('c'));//true
            console.log(map.has('d'));//false
        </script>
    </body>
</html>

5、delete(key)方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>map中的delete方法</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map();
            map.set('a',1);
            console.log(map.has('a'));//true
            map.delete('a');//删除键a
            console.log(map.has('a'));//false
        </script>
    </body>
</html>

6、clear()方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>map中的clear()方法</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map();
            map.set('foo',true);//向map中添加成员
            map.set('bar',false);
            console.log(map.size);//2
            map.clear();//清除map中的全部成员
            console.log(map.size);//0
        </script>
    </body>
</html>

7、遍历方法keys()、values()、entries()、forEach()

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>遍历方法keys(),values(),entries(),forEach()</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map();
            //向map中添加成员
            map.set(1,'a');
            map.set(2,'b');
            map.set(3,'c');
            //遍历全部的键
            for(let key of map.keys()){
                console.log(key);/* 1                  
                      2                                        
                      3
*/
        } 
        //遍历全部的值
        for(let values of map.values()){
          console.log(values);/
* a                 
                        b                                        
                        c
*/
        } 

        //遍历全部的键和值
        for(let [key,value] of map.entries()){
          console.log(key,value);
/*1 'a'
                         2 'b'
                         3 'c'*/
        } 
       for(let [key,value] of map){
          console.log(key,value);
/*1 'a'
                         2 'b'
                         3 'c'*/
        } 
       map.forEach(
function(value,key){
          console.log(key,value);
/*1 'a'
                          2 'b'
                          3 'c'*/
       }) 
    </script>
  </body>
</html>

8、Map结构转为数组<!DOCTYPE html><html>

<!DOCTYPE html>
<html>
   <head>
        <meta charset="UTF-8">
        <title>map结构转为数组</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map([
                [1,'one'],
                [2,'two'],
                [3,'three']
            ]);
            console.log([...map.keys()]);//(3) [1, 2, 3]
            console.log([...map.values()]);//(3) ['one', 'two', 'three']
            console.log([...map]);
       /*
(3) [Array(2), Array(2), Array(2)]
      1.   0(2) [1'one']
      2.   1(2) [2'two']
      3.   2(2) [3'three']
      4.   length3
      5.   [[Prototype]]Array(0) */
         console.log([...map.entries()]);
       /*(3) [Array(2), Array(2), Array(2)]
    1.         0(2) [1'one']
    2.         1(2) [2'two']
    3.         2(2) [3'three']
    4.         length
    5.            [[Prototype]]Array(0) */
       const map1=new Map( [...map].filter(([key,value])=>key<3)//使用数组的filter方法  ); 
       console.log(map1);
//Map(2) {1 => 'one', 2 => 'two'}
    </script>
  </body>
</html>

三、Map与其它数据结构的转换

作为键值对存储数据的Map与其它数据也可以进行转换,我们看下下面的案例

1、Map转为数组

 Map转为数组最方便的方法,就是使用扩展运算符...

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Map转为数组</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map();//创建map数据结构
            map.set(true,7);//向map中添加成员
            map.set({foo:3},['abc']);
            console.log([...map]);
       /*(2) [Array(2), Array(2)]
        0(2) [true7]
      1.  1(2) [{…}Array(1)]
      2.  length2
      3.  [[Prototype]]Array(0) */  
        </script>
    </body>
</html>

2、数组转为Map

 将数组传入Map构造函数,就可以转为Map<!DOCTYPE html>

<html>
    <head>
        <meta charset="UTF-8">
        <title>数组转为map</title>
    </head>
    <body>
        <script type="text/javascript">
            const map=new Map([
                [true,7],
                [{foo:3},['abc']]
            ]);
            console.log(map);
            /*map{
                true=>7,
                object:{foo:3}=>['abc'];
            }*/
</script> </body> </html>

3、Map转为对象

如果所有Map的键都是字符串,它可以无损的转为对象,如果有非字符串的键名,那么这个键名会被转为字符串,再作为对象的键名

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>map转为对象</title>
    </head>
    <body>
        <script type="text/javascript">
            function strMapObj(strMap){
                let obj=Object.create(null);//创建一个新对象
                for(let [key,value] of strMap){//遍历循环strMap
                    obj[key]=value;
                }
                return obj;
            }
            const map=new Map().set('yes',true).set('no',false);
            console.log(strMapObj(map));//{yes: true, no: false}
        </script>
    </body>
</html>

在这里了我需要讲解一下Object.create()这个方法,官方的意思是:Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>测试Object.create()方法</title>
    </head>
    <body>
        <script type="text/javascript">
            const person={
                isHuman: false,
                  printIntroduction: function () {
                    console.log(this.name,this.isHuman);
                  }
            }
            const me = Object.create(person);
            me.name = "Matthew";
            me.isHuman = true;
            me.printIntroduction();//Mattew,true
        </script>
    </body>
</html>

4、对象转为Map

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>对象转为map</title>
    </head>
    <body>
        <script type="text/javascript">
            function objToMap(obj){
                let map=new Map();
                for(let key of Object.keys(obj)){
                    map.set(key,obj[key]);
                }
                return map;
            }
            console.log(objToMap({yes:true,no:false}));//Map(2) {'yes' => true, 'no' => false}
        </script>
    </body>
</html>

在这里讲解Object.keys()方法,官方解释:Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用,for..in循环遍历该对象时返回的顺序一致 。如果对象的键-值都不可枚举,那么将返回由键组成的数组。

参数:

要返回其枚举自身属性的对象

返回值:

一个表示给定对象的所有可枚举属性的字符串数组

// simple array
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // (3) ['0', '1', '2']

// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // (3) ['0', '1', '2']

// array like object with random key ordering
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // (3) ['2', '7', '100']

// getFoo is a property which isn't enumerable
var myObj = Object.create({}, {
  getFoo: {
    value: function () { return this.foo; }
  } 
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // ['foo']

5、Map转为JSON字符串

Map转为json要区分两种情况,一种情况时Map的键名都是字符串,这时可以选择转为对象json,另一种情况是Map的键名有非字符串,这时可以选择转为数组json。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>map转为json</title>
    </head>
    <body>
        <script type="text/javascript">
            function strMapToObj(strMap){
                let obj=Object.create(null);//创建一个新对象
                for(let [key,value] of strMap){
                    obj[key]=value;
                }
                return obj;
            }
            function strMapToJson(strMap){
                return JSON.stringify(strMapToObj(strMap));
            }
            let map=new Map().set('yes',true).set('no',false);
            let obj=strMapToJson(map);
            console.log(obj);//{"yes":true,"no":false}
            function mapToArrayJson(map){
                return JSON.stringify([...map]);
            }
            let fooMap=new Map().set(true,7).set({foo:3},['abc']);
            let foo=mapToArrayJson(fooMap);
            console.log(foo);//[[true,7],[{"foo":3},["abc"]]]
        </script>
    </body>
</html>

6、JSON字符串转为Map

json转为Map,正常情况下所有键名都是字符串,但是有一种特殊情况,整个json就是一个数组,且每个数组成员本身,又是一个有两个成员的数组,这时它可以一一对应的转为Map,这往往是Map转为数组json的逆操作。<!DOCTYPE html><html>

    <head>
        <meta charset="UTF-8">
        <title>json转为map</title>
    </head>
    <body>
        <script type="text/javascript">
            function objTostrMap(obj){
                let map=new Map();
                for(let key of Object.keys(obj)){
                    map.set(key,obj[key]);
                }
                return map;
            }
            function jsonToStrMap(jsonStr){
                return objTostrMap(JSON.parse(jsonStr));
            }
            let obj1=jsonToStrMap('{"yes": true, "no": false}')
            console.log(obj1);//Map(2) {'yes' => true, 'no' => false}
            function jsonToMap(jsonStr){
                return new Map(JSON.parse(jsonStr));
            }
            let obj2=jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
            console.log(obj2);
          /*map{
                true=>7,
                object:{foo:3}=>['abc'];
              }*/
    </script> 
  </body>
</html>

二、与Set的区别

.Map是键值对,Set是值的集合,当然键和值可以是任何的值;

2.Map可以通过get方法获取值,而set不能因为它只有值;

3.都能通过迭代器进行for...of遍历;

4.Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储

5.map和set都是stl中的关联容器,map以键值对的形式存储,key=value组成pair,是一组映射关系。set只有值,可以认为只有一个数据,并且set中元素不可以重复且自动排序。

Set(3) {2, 4, 6}

posted on 2021-10-14 22:13  黑土土  阅读(253)  评论(0)    收藏  举报

导航