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的区别:
- WeakSet中只能存放对象类型,不可以存放基本数据类型;
- WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收;
-
const weakSet = new WeakSet(); //会报错 只能存放对象 TypeError weakSet.add(10) //WeakSet常见方法: add(value):添加某个元素,返回WeakSet对象本身; delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型; has(value):判断WeakSet中是否存在某个元素,返回boolean类型; -
WeakSet不能遍历
- 因为WeakSet只是对象的弱引用,如果我们遍历获取其中的元素,那么可能造成对象不能正常的销毁;
- 所以存储到WeakSet中的对象是没有办法获取的;
3、Map
-
另外一个新增的数据结构是Map,用于存储映射关系;
-
但是我们之前可以使用对象来存储映射关系,它们之间有什么区别?
- 事实上我们对象存储映射关系只能用字符串(ES6新增了Symbol)作为属性名(key)
- 某些情况下我们可能希望通过其他类型作为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主要的区别:
- WeakMap的key只能使用对象,不接受其他类型的作为key;
- 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 => { ************** })