美文网首页
ES6的Map、Set和ES7的Array.includes()

ES6的Map、Set和ES7的Array.includes()

作者: 咸鱼不咸_123 | 来源:发表于2022-05-11 10:24 被阅读0次

    一、ES6

    1.Set

    1.Set的基本使用

    • 在ES6之前,我们存储数据的结构主要有两种:数组、对象。
    • 在ES6中新增了另外两种数据结构:Set、Map,以及它们的另外形式WeakSet、WeakMap

    数据结构:存储数据的方式

    • Set是一个新增的数据结构,可以用来保存数据,类似于数组,但和数组最大的区别是 元素不能重复

      • 创建Set我们需要使用Set构造函数(暂时没有字面量创建的方式)
    • 应用场景

      • 添加的元素希望不重复
      • 给数组去重
        • new Set(arr)
        • 转化为数组
          • Array.from()
          • 展开运算符
    // 10,20,40,333
    // * 创建Set结构
    let set=new Set();
    // * 添加元素
    set.add(10)
    set.add(20)
    set.add(40)
    set.add(333)
    set.add(10);//重复的元素会被忽略
    
    // * 添加对象的注意点
    set.add({});//两个对象是有不同的内存地址
    set.add({});//和上面的{}的地址是不同的
    
    const obj={name:"wjy"};
    set.add(obj); 
    set.add(obj); //*重复的内存地址也只会被添加一次
    console.log(set);
    
    
    // * 应用场景:①不想添加的元素重复  ② 给数组去重
    const arr=[22,10,20,45,22,10,2];
    
    // * 1.自己写的一个方法
    const newArr=[];
    for(const item of arr){
      if(newArr.indexOf(item)==-1){
        newArr.push(item)
      }
    }
    // * 可以使用Set
    const arrSet=new Set(arr);
    // * 方法1  Array.from
    const newArr2=Array.from(arrSet);//* Array.from():对一个类似数组或可迭代对象创建一个新的、浅拷贝的数组实例
    console.log(newArr2);
    // * 方法2:展开运算符
    const newArr3=[...arrSet];
    console.log(newArr3);
    
    

    2.Set常见的属性和方法

    2.1 常见的属性
    • size:获取set的元素个数
    console.log(set.size);
    
    2.2 常见的方法
    • add(item):添加指定的元素,如果存在,则不添加
    • delete(item):删除指定的元素
    • has(item):判断指定的item是否在Set中
    • clear():清空Set集合
    • 遍历
      • forEach遍历
      • for...of
    /**
     * * 常见的方法
     * * 1. add(item):添加指定元素
     * * 2. delete(item):删除指定元素
     * * 3.has(item):判断指定元素是否在Set中,如果有则返回true,否则返回false
     * * 4.clear():清空Set集合
     */
    
    set.add("wjy");
    console.log(set);
    set.delete("wjy");
    console.log(set);
    console.log(set.has("wjy"));
    set.forEach(item=>{
      console.log(item);
    })
    
    for(const item of set){
      console.log(item);
    }
    set.clear();
    console.log(set);
    

    2.WeakSet

    和Set类似的另外一个数据结构称之为WeakSet,也是内部元素不能重复的数据结构。

    • 那么和Set有什么区别呢?
      • 区别一:WeakSet只能存放对象类型,不能存放基本数据类型
      • 区别二:WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收。

    强引用指的的是 指向的那条线是生效的。

    弱引用指的是指向的那条线存在不存在,没有任何关系。

    let obj={name:"why"};
    let set=new Set();
    set.add(obj);
    console.log(set);
    
    image-20220510185545267.png

    如果将obj设置为null,set存储的元素也还是会被引用。

    obj=null;
    console.log(set);
    
    image-20220510185619772.png

    但如果是 WeakSet,因为WeakSet对元素的引用是弱引用,所以由weakSet指向那片地址其实没有用的,不算真正的引用,如果初略WeakSet本身实例指向那片地址,没有其他引用引用这个对象的话,这个对象会被GC回收掉。

    const weakSet=new WeakSet();
    let obj={name:"why"};
    weakSet.add(obj);
    
    image-20220510185836514.png
    obj=null;
    

    当obj不再引用这片地址空间时,没有其他引用引用了,除了weakSet本身的弱引用(但是这个弱引用是没有用的),这片内存空间会被GC回收掉。

    image-20220510190221909.png

    2.1 WeakSet的常用方法

    • add(item):添加某个元素,返回WeakSet对象本身
    • delete(item):从WeakSet中删除和这个值相等的元素,返回boolean类型
    • has(value):判断WeakSet中是否存在某个元素,返回boolean类型

    注意:WeakSet不能遍历

    • 因为WeakSset只是对对象的弱引用,如果我们遍历获取到其中的元素,那么有可能造成对象不能正常的销毁
    • 所以存储到WeakSet是没办法正常获取的。

    2.2 应用场景

    我们使用一个Stack Overflow上的答案:只能使用Person实例调用running,相对于Set比较方便,不需要手动是释放内存。

    let weak=new WeakSet();
    class Person{
      constructor(){
        weak.add(this);
      }
      running(){
        if(!weak.has(this)) throw new Error("Type Error ,NOT Person")
        console.log("running");
      }
    }
    
    const p=new Person();
    p.running.call({name:'wjy'});
    

    3.Map

    另外一个新增的数据结构是Map,用于存储映射关系。

    但是我们可能会想,在之前我们可以使用对象来存储映射关系,他们有什么区别呢?

    • 事实上我们对象存储映射关系只能使用字符串(ES6中新增了Symbol)作为属性名(key)
    • 某些情况下我们可能希望通过其他类型作为key,比如key,这个时候会自动将对象转化为字符串来作为key
    let obj1={name:"wjy"};
    let obj2={name:"hyz"};
    
    let o={
      [obj1]:'aaa',
      [obj2]:'bbb'
    }
    
    //* 因为对象后面被直接转换为 字符串[object Object],所以当同样的key被重复赋值时,只会保留最新的值。
    //* []:这个是计算属性
    console.log(o);//{ '[object Object]': 'bbb' }
    

    那么我们就可以使用Map:

    • new Map() 创建一个Map实例对象
    • set(key,value)
    // * Map允许对象作为key
    let map=new Map();
    let obj1={name:"wjy"};
    let obj2={name:"hyz"};
    map.set(obj1,"aaa");
    map.set(obj2,"bbb")
    map.set("name","wjy")
    console.log(map);
    // Map(3) {
    //   { name: 'wjy' } => 'aaa',
    //   { name: 'hyz' } => 'bbb',
    //   'name' => 'wjy'
    // }
    
    let map2=new Map([[obj1,"aaa"],[obj2,"bbb"],["name","wjy"]]);//可以传入数组
    
    console.log(map2);
    // Map(3) {
    //   { name: 'wjy' } => 'aaa',
    //   { name: 'hyz' } => 'bbb',
    //   'name' => 'wjy'
    // }
    

    3.1 常用的方法和属性

    Map常见的属性:

    • size:返回Map的元素的个数

    Map常用的方法:

    • set(key,value):在Map中添加key和value,并将整个Map对象返回。
    • get(key):根据key获取Map中的value。
    • has(key):判断是否包含某个key,返回Boolean类型。
    • delete(key):根据key删除一个键值对,返回Boolean类型。删除成功,返回true,删除失败,返回false
    • clear():清空map
    • 遍历
      • forEach((value,key)=>{})
      • for....of
        • 数组类型,第一个元素是key,第二个元素是value
    /**
     * * 常用属性
     * * size:获取Map的元素个数
     */
    
    console.log(map2.size);//3
    /**
     * * 常用方法
     * * set:添加一个key和value,并将整个Map对象返回
     * * get:根据key获取Map中的value
     * * has:判断是否包含某个key,返回Boolean
     * * delete:根据key,删除键值对,删除成功返回true,删除失败返回false
     * * clear:清空
     */
    
    console.log(map2.get(obj1));//aaa
    console.log(map2.has("name"));//true
    console.log(map2.delete("aa"));//false
    map2.clear();
    console.log(map2);//Map(0) {}
    

    4.WeakMap

    和Map类型相似的另外一个数据结构称之为WeakMap,也是以键值对的形式存在的。

    那么和Map有什么区别呢?

    • WeakMap的key只能使用对象,不能使用基本数据类型
    • WeakMap的key对对象的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象。

    Map是对key的强引用,WeakMap是对key的弱引用(这个引用是没有关系的)

    let  obj1={name:"obj1"};
    const map=new Map();
    map.set(obj1,"aaaa");
    
    image-20220510213359653.png
    obj1=null
    

    将obj1指向null,不指向那片内存空间,但是由于Map中对key的引用是强引用,所以并不会被回收掉的。

    image-20220510213530774.png

    但如果是WeakMap结果就是不一样的了。

    let  obj1={name:"obj1"};
    const map=new WeakMap();
    map.set(obj1,"aaa");
    
    image-20220510214123411.png
    obj1=null;
    

    将obj1指向null,不再指向那片空间,由于在weakMap中是弱引用,所以那片空间是可以被GC回收的。

    image-20220510214717212.png

    4.1 常见方法

    • set (key,value):向WeakMap中添加key,value值,并将整个WeakMap对象返回
    • get(key):根据key返回Map中的value
    • has(key):判断是否包含一个key,返回Boolean类型
    • delete(key):根据key删除一个键值对,返回Boolean类型

    不能遍历

    • 没有forEach
    • 也不能使用for...of
    let  obj1={name:"obj1"};
    const map=new WeakMap();
    map.set(obj1,"aaa");
    
    
    
    /**
     * * 常见的方法
     * * set
     * * get
     * * delete
     * * has
     */
    console.log(map.get(obj1));//aaa
    console.log(map.has(obj1));//true
    console.log(map.delete(obj1));//true
    

    4.2 应用场景

    • Vue3响应式应用场景
    let obj1={name:"wjy",age:20};
    function obj1NameFn1(){
      console.log("obj1NameFn1被执行了");
    }
    
    function obj1NameFn2(){
      console.log("obj1NameFn2被执行了");
    }
    
    function obj1AgeFn1(){
      console.log("obj1AgeFn1被执行了");
    }
    
    function obj1AgeFn2(){
      console.log("obj1AgeFn2被执行了");
    }
    
    
    let obj2={
      name:"kobe",
      height:1.88,
      address:"广州市"
    }
    
    function obj2NameFn1(){
      console.log("obj2NameFn1被执行了");
    }
    
    function obj2NameFn2(){
      console.log("obj2NameFn2被执行了");
    }
    // 1. 创建一个WeakMap
    let weakMap=new WeakMap();
    
    // 2.1 收集依赖数据结构:对obj1收集的数据结构
    
    const obj1Map=new Map();
    obj1Map.set("name",[obj1NameFn1,obj1NameFn2]);
    obj1Map.set("age",[obj1AgeFn1,obj1AgeFn2]);
    weakMap.set(obj1,obj1Map)
    
    // 2.2.收集依赖数据结构
    const obj2Map=new Map();
    obj2Map.set("name",[obj2NameFn1,obj2NameFn2]);
    weakMap.set(obj2,obj2Map)
    
    // 3 如果obj1.name发生了改变
    // Proxy/Object.defineProperty
    obj1.name="james";
    const targetMap=weakMap.get(obj1);
    const fns=targetMap.get("name");
    fns.forEach(item=>item())
    

    二、ES7

    1.Array Includes

    在ES7之前,如果我们想判断一个数组中是否包含某个元素,需要通过indexOf获取结果,并且判断是否为-1

    在ES7之后,我们可以通过includes来判断一个数组中是否包含一个指定的元素,根据情况,如果包含则返回true,否则返回false

    语法:

    Array.includes(item,startIndex)
    
    • item:必需参数
    • startIndex:可选,从哪个位置开始查找
    const names=["wjy","hyz","tl"];
    
    if(names.indexOf("abc")!==-1){ //阅读性差
      console.log("包含");
    }
    
    // ES7 Array.includes():判断数组是否包含某个元素
    // includes(item,startIndex); startIndex:从哪个位置开始判断
    if(names.includes("wjy",0)){
      console.log("包含");
    }
    

    1.1 Array.includes和Array.indexOf的区别

    如果数组中有个元素为NaN,

    如果使用indexOf判断NaN是否存在,它会返回-1(找不到NaN这个元素)

    如果使用includes判断NaN是否存在,它会返回true(找到了这个NaN元素)

    const names=["wjy","hyz","tl",NaN];
    if(names.indexOf(NaN)!==-1){  //* 即使数组中有NaN,但还是被判断为不存在
      console.log("包含NaN");
    }
    
    if(names.includes(NaN)){
      console.log("包含NaN");
    }
    

    2.指数(乘方运算)

    在ES7之前,计算数字的乘方需要使用Math.pow方法来完成。

    在ES7中,增加了**运算符,可以对数字来计算乘方。

    // 计算3的3次方
    
    // ES7之前
    const result1=Math.pow(3,3);
    // ES7后
    const result2=3**3;
    
    console.log(result1==result2);//true
    

    三、总结

    ES6的Set、WeakSet、Map、WeakMap和ES7的Array.includes和乘方.png

    相关文章

      网友评论

          本文标题:ES6的Map、Set和ES7的Array.includes()

          本文链接:https://www.haomeiwen.com/subject/qxddurtx.html