ES6(1)|青训营笔记

109 阅读5分钟

1、Set的基本使用(16)

  • 在ES6之前,我们存储数据的结构主要有两种:数组、对象;

  • 在ES6中新增了两种数据结构:Set、Map,以及它们的另外形式WeakSet、WeakMap;

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

  • 创建Set我们需要通过Set构造函数(暂时没有字面量创建的方式)

    const set = new Set();
    //往集合里添加元素 数字一样 只添加一次 
    set.add(10);
    set.add(10);
    //Set(1){10};
    console.log(set);
    //添加对象需要注意,对象的引用地址是否是一样的
    set.add({});
    set.add({});
    //Set(2){{},{}}
    console.log(set);
    

-- 使用途径:给数组去重

  • const arr = [22,1,3,4,3,2,1];
    //原来去重方式
    const newArr = [];
    for(const item of arr){
      if(newArr.indexOf(item)!==-1){
        newArr.push(item);
      }
    }
    //有了Set以后
    const arrSet = new Set(arr);
    console.log(arrSet);
    //将Set转为数组
    const newArr = Array.from(arrSet)
    //也可以这样写
    const newArr = [...arrSet];
    

-Set属性与方法

//size属性
console.log(arrSet.size);
//Set方法
//1.0 添加元素
arrSet.add(100);
//2.0删除元素 这里必须要传元素进去 不支持通过索引删除某个元素
arrSet.delete(100);
//3.0 判断是否包含某个元素
arrSet.has(100);
//4.0清楚这个set
arrSet.clear();
//5.0对set遍历 两种方式 
arrSet.forEach(item => {
  console.log(item);
});
for(const item of arrSet) {
  console.log(item);
}

2、WeakSet

  • 和Set类似,也是内部元素不可以重复的数据结构;

  • 和Set的区别:

    1. WeakSet中只能存放对象类型,不可以存放基本数据类型;
    2. WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收;
  • const weakSet = new WeakSet();
    //会报错 只能存放对象 TypeError
    weakSet.add(10)
    ​
    //WeakSet常见方法:
    add(value):添加某个元素,返回WeakSet对象本身;
    delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型;
    has(value):判断WeakSet中是否存在某个元素,返回boolean类型;
    
  • WeakSet不能遍历

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

3、Map

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

  • 但是我们之前可以使用对象来存储映射关系,它们之间有什么区别?

    1. 事实上我们对象存储映射关系只能用字符串(ES6新增了Symbol)作为属性名(key)
    2. 某些情况下我们可能希望通过其他类型作为key,比如对象,这个时候会自动将对象转换成字符串来作为key;
  • const obj1 = {name:"why"};
    const obj1 = {name:"kobe"};
    //Map创建方式一
    const map = new Map();
    //Map可以使用对象作为key
    map.set(obj1,"aaa");
    map.set(obj1,"bbb");
    //Map(2){{name:'why'} => 'aaa',{name:'kobe'} => 'bbb'}
    console.log(map);
    ​
    //Map创建方式二:
    const map1 = new Map([[obj1,"aaa"],[obj2,"ccc"],[2,"ddd"]]);
    ​
    //常见的方法与属性
    //属性
    console.log(map.size);
    //方法1:添加数据
    map.set(obj1,"aaa");
    //方法2:获取key
    map.get(key);
    //方法3:是否存在?
    map.has(key);
    //方法4:删除
    map.delete(key);
    //方法5:清除
    map.clear();
    ​
    //遍历方式:
    map.forEach(item => {
      //只会打印出对应的key
      console.log(item);
    })
    ​
    map.forEach((item,key) => {
      //可以打印出key:value
      console.log(item,key);
    })
    //遍历方式2:
    for(const item of map) {
      console.log(item);
    }
    

    4、WeakMap

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

  • 他和Map主要的区别:

    1. WeakMap的key只能使用对象,不接受其他类型的作为key;
    2. WeakMap的key是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象;
  • //常见方法(没有size属性)
    const weakMap = new WeakMap();
    weakMap.get(obj);
    //WeakMap{<items unknown>} 因为不可以遍历
    console.log(weakMap.get(obj))
    weakMap.has(obj);
    weakMap.delete(obj);
    
  • 应用场景(Vue3响应式原理)

    //模拟一个响应式案例,vue中需要监听某些数据发生改变,然后要在浏览器相应的地方做出改变,此时就是监听对象中某些值发生改变,然后调用与这些值相互关联的函数,进行修改页面中的数据;
    const weakMap = new WeakMap();
    const obj1 = {
      name: "why",
      age:18
    };
    //与obj1 name值相关联的函数
    function obj1NameFn1() {
      console.log("obj1NameFn1")
    };
    function obj1NameFn2() {
      console.log("obj1NameFn2")
    };
    //与obj1 age值相关联的函数
    function obj1AgeFn1() {
      console.log("obj1AgeFn1")
    };
    function obj1AgeFn2() {
      console.log("obj1AgeFn2")
    };
    ​
    const obj2 = {
      name: "zwx",
      age: 20
    };
    //与obj2 name值相关联的函数
    function obj2NameFn1() {
      console.log("obj2NameFn1")
    };
    function obj2NameFn2() {
      console.log("obj2NameFn2")
    };
    //与obj2 age值相关联的函数
    function obj2AgeFn1() {
      console.log("obj2AgeFn1")
    };
    function obj2AgeFn2() {
      console.log("obj2AgeFn2")
    };
    ​
    //收集依赖结构
    const obj1Map = new Map();
    //建立起与obj1里面各个属性相关联的函数 这里只能使用Map WeakMap的key只能是对象
    obj1Map.set("name",[obj1NameFn1,obj1NameFn2]);
    obj1Map.set("age",[obj1AgeFn1,obj1AgeFn2]);
    //保存与obj1相关的映射关系//这里使用WeakMap是因为一旦需要销毁obj1,如果使用Map,则Map中包含着对其引用,GC不能回收,但是使用WeakMap,obj1一旦设置为null,GC就可以对他进行回收
    weakMap.set(obj1,obj1Map);
    ​
    const obj2Map = new Map();
    //建立起与obj2里面各个属性相关联的函数
    obj2Map.set("name",[obj2NameFn1,obj2NameFn2]);
    obj2Map.set("age",[obj2AgeFn1,obj2AgeFn2]);
    //保存与obj2相关的映射关系
    weakMap.set(obj2,obj1Map);
    ​
    //如果obj1.name发生改变
    //可以通过Proxy/Object.defineProperty监听到数据的改变
    obj1.name = "james;
    //发生改变后,可以从weakmap中拿到与obj1关联的函数
    const targetMap = weakMap.get(obj1);
    //拿到obj1中与name相关联的函数
    const fns = targetMap.get("name");
    //由于Map中可以使用forEach进行遍历 可以分别遍历与obj1 name 相关联的函数
    fns.forEch(item => {
      **************
    })