new Set
1. 什么是Set()
new set()是 es6 新增的数据结构,类似于数组,但它的一大特性就是所有元素都是唯一的,没有重复的值,我们一般称为集合,Set本身是一个构造函数,用来生成 Set 数据结构。
应用场景:
-
用于数组去重、用于字符串去重
-
判断元素是否存在
-
集合运算(交集、并集、差集)
注意:类似于数组,但是它是个对象类型
2. 增删改查方法
2.1 添加元素-----add()
添加某个值,返回 Set 结构本身,当添加实例中已经存在的元素,set不会进行处理添加
let list = new Set([5,6,6]);
list.add(1);
list.add(2).add(3).add(3); // 3只被添加了一次
console.log(list) // {5, 6, 1, 2, 3}
2.2 删除元素-----delete()
删除某个值,返回一个布尔值,表示删除是否成功
let list=new Set([1,20,30,40])
list.delete(30) // true //删除值为30的元素,有返回true,没有返回false
console.log(list) // {1, 20, 40}
2.3 判断某元素是否存在-------has()
返回一个布尔值,判断该值是否为Set的成员
let list=new Set([1,2,3,4])
list.has(2) // 有返回true,没有返回false
2.4 清除所有元素------clear()
清除所有成员,没有返回值
let list=new Set([1,2,3,4])
list.clear()
console.log(list) // {}
3. 遍历方法
3.1 遍历 keys()
返回键名的遍历器,相等于返回键值遍历器values()
let list2=new Set(['a','b','c'])
for(let key of list2.keys()){
console.log(key)//a,b,c
}
3.2 遍历 values()
返回键值的遍历器
let list=new Set(['a','b','c'])
for(let value of list.values()){
console.log(value)//a,b,c
}
3.3 遍历 entries()
返回键值队的遍历器
let list=new Set(['4','5','hello'])
for (let item of list.entries()) {
console.log(item);
}
// ['4','4'] ['5','5'] ['hello','hello']
3.4 遍历 forEach()
使用回调函数遍历每个成员
let list=new Set(['4','5','hello'])
list.forEach((value, key) => console.log(key + ' : ' + value))
// 4:4 5:5 hello:hello
4. 使用情形
4.1 用于数组去重
let arr = [3, 5, 2, 2, 5, 5];
let setArr = new Set(arr) // 返回set数据结构 Set(3) {3, 5, 2}
//方法一 es6的...解构
let unique1 = [...setArr ]; //去重转数组后 [3,5,2]
//方法二 Array.from()解析类数组为数组
let unique2 = Array.from(setArr ) //去重转数组后 [3,5,2]
4.2 用于字符串去重
let str = "352255";
let unique = [...new Set(str)].join(""); // 352
4.3 实现并集、交集、和差集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
// (a 相对于 b 的)差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}
弊端
问题:当 set
中的值被 null 掉了后,它还会一直在里面,但是操作不了
let obj = {
name: 'aa'
}
let s1 = new Set()
s1.add(obj).add('aaa')
// 值
0: {name: 'aa'}
1: "aaa"
console.log(set.has(obj)); // true
//-----------------------------------------------------------------------
// 但是如果 obj = null 就查找不到了但是值是有的
obj = null
console.log(set.has(obj)); // false
for(let i of s1) {
console.log(i);
}
// 值
{name: 'aa'}
"aaa"
// 这个时候,这个值就操作不了了
解决办法:weakset
let obj = {
name: 'aa'
}
let s1 = new WeakSet()
s1.add(obj)
obj = null
console.log(s1); // 这个时候里面是空的
new WeakSet
弱集
(强引用)是垃圾收集值的集合,包括对象和未注册的符号。
注意:
-
weakSet
只能添加复杂类型 -
不存在引用计数+1
-
size,for不能用了,因为里面的数不确定
1. 添加值
let wset = new WeakSet();
let obj = {
name: "小明"
}
wset.add(obj)
2. 查询值
console.log(wset.has(object)); // flase
console.log(wset.has(obj)); // true
3. 移除值
wset.delete(obj)
console.log(wset.has(obj)); // false
new Map
Map类型是键值对的有序列表,而键和值都可以是任意类型
Map
对象是键值对的集合。Map
中的一个键只能出现一次;它在 Map
的集合中是独一无二的。
应用场景:
-
数据库操作
-
Map可以用来存储查询结果。例如我们可以将查询结果的每一行数据存储在一个Map中,其中键为列名,值为该列对应的值。这样我们就可以方便地获取每一行数据的任意一列的值。
-
-
缓存
-
计算值
1. Map与Set的区别
-
Set是一种叫做集合的数据结构,Map是一种叫做字典的数据结构
集合-----是由一堆无序的、相关联的,且不重复的内存结构【数学中称为元素】组成的组合 字典-----是一些元素的集合。每个元素有一个称作key 的域,不同元素的key 各不相同
-
Set集合是以[值,值]的形式存储元素, Map字典是以[键,值]的形式存储
2 添加键
使用 set()
来添加
const map = new Map();
let obj = {
name: "小明"
}
map.set(obj,"111") // 第一个是键 第二个是值
// 可采用链式写法
map.set('flag', true).set('a',6);
3. 读取值
使用 get()
来添加,获取不到返回 undefined
map.get('flag') // true
4. 成员的数量
size
是可访问属性,返回 Map
对象的成员数量。
console.log(map.size); // 3
5. 移除对象中的所有元素
clear()
方法会移除 Map
对象中的所有元素。
map.clear()
console.log(map.size); // 0
6. 查询对象中是否包含指定元素
has()
方法返回一个布尔值,指示具有指定键的元素是否存在,如果没有返回 false
。
console.log(map.has('a')); // true
console.log(map.has('b')); // false
7. 移除对象中的指定元素
delete()
方法用于移除 Map
对象中指定的元素。
map.delete('a')
console.log(map.has('a')); // false
8. 遍历
3.1 遍历 keys()
返回键名的遍历器,相等于返回键值遍历器values()
for(let key of map.keys()){
console.log(key)
}
// {name: "小明"} flag a
3.2 遍历 values()
可以拿到索引的键值
console.log(map.values())
// 0 111
// 1 true
// 2 6
返回键值的遍历器
for (let item of map.values()) {
console.log(item);
}
// 111 true 6
3.3 遍历 entries()
返回键值队的遍历器
for (let item of map.entries()) {
console.log(item);
}
// [{name: "小明"},'111'] ['flag',true] ['a', 6]
3.4 遍历 forEach()
forEach()
方法按照插入顺序依次对 Map
中每个键/值对执行一次给定的函数。
map.forEach(element => {
console.log(element);
});
// 111 true 6
弊端
// 如果把 obj 给 nulll
obj = null
// 它会跟 set 一样没有回收掉
解决办法:weakMap
跟 WeakSet 差不多,都是解决这个问题的,不会添加回收的,有回收机制
let obj = {
name: "aa"
}
let m1 = new WeakMap()
m1.set(obj, "111")
obj = null
new WeakMap
WeakMap
对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的
1. 添加值
const wmap = new WeakMap();
const obj = {
name: "小明"
};
wmap.set(obj, '6');
2. 读取值
wmap.has(obj); // true
3. 获取指定键的值
wmap.get(obj) // 6
4. 移除值
wmap.delete(obj)
console.log(wmap.has(obj)); // false
案例:
当按钮失效了,点击数也要清空
<button id="like">like</button>
<script>
let wmap = new WeakMap()
let like = document.getElementById('like')
wmap.set(like,{click: 0})
like.onclick = function(){
let times = wmap.get(like)
times.click++
}
setTimeout(function(){
document.body.removeChild(like)
// like 需要把变量为空,要不他 dom 节点没了,但是变量还有内容
like = null
},2000)
// --------------- 另一种方法
// 不使用变量获取dom
let wmap = new WeakMap()
wmap.set(document.getElementById('like'),{click: 0})
document.getElementById("like").addEventListener('click',()=>{
let times = wmap.get(document.getElementById('like'))
times.click++
},false)
setTimeout(function(){
document.body.removeChild(document.getElementById("like"))
},2000)
</script>
WeakRef
WeakRef 对象允许您保留对另一个对象的弱引用,而不会阻止被弱引用对象被 GC 回收
强引用是指一个对象被其他对象强烈地引用,只要有强引用存在,被引用的对象就不会被垃圾回收器回收。换句话说,只有当所有强引用都不存在时,对象才会被回收。
弱引用是一种比较弱的引用关系,当一个对象只被弱引用引用时,垃圾回收器可能会在下一次运行时将其回收。弱引用通常用于缓存、观察者模式等场景,可以避免内存泄漏问题。
优化案例,使用 WeakRef
<button id="like">like</button>
<script>
let wmap = new WeakMap()
// 拿不到值直接就是 underline,wmap 直接就会被回收机制给清空了
let like = new WeakRef(document.getElementById('like'))
// 使用 deref() 来拿到值
wmap.set(like.deref(),{click: 0})
like.deref().onclick = function(){
let times = wmap.get(like.deref())
times.click++
}
setTimeout(function(){
document.body.removeChild(like.deref())
},2000)
</script>