ES6数据结构:Set,WeakSet,Map,WeakMap
前言
我们说基本数据类型有symbol
、null
、数值
、boolean
、string
、undefined
、大数值
,引用数据类型有function
、object
...为什么要划分这两种数据类型呢?引用数据类型和基本数据类型最本质的区别有一个就是一个存放在栈
里面一个存放在堆
里面,那么今天要介绍的es6中新增加的两种数据类型set
、map
,也是引用数据类型。
Set
- Set的成员都是唯一的,不可以重复
set集合的创建
// set的创建
const s1 = new Set()
s1.add(1)
s1.add(1)
console.log(s1) //{1}
const s2 = new Set([1,2,2])
console.log(s2) //{1,2}
set身上的一些方法:
- 我们把他放到浏览器上去看,更加直观,可以看见他长得和对象一样,但是他没有key,value,但是你要说这是一个对象也没错,引用数据类型也可以称之为对象
- Set集合内置属性
size
,返回集合的长度,和数组一样,有一个length属性,可以看到,他有一个Entries属性
,存放的123,他有下标012,因为我们往set这种数据结构中放入值的时候,这个key是默认不需要我们操作的,默认从0开始,不存在重复项,因此我们又称之为类数组
- 我们从浏览器中可以看到从他的原型中可以找到很多方法方法,比如
values方法
获取这个集合的值,但是我们没有办法把其中的某一个值拿出来,只能通过value方法拿出所有的值 - 其中还能看到有一个
has方法
,用于判断集合中是否存在某一个值 s.delete(2)
,delete方法删除某一个值s.clear()
,清空集合s.keys()
获取键名,s.values
获取键值,s.entries()
获取键值对,但是返回的键值对是以数组的形式存放
- set这种数据结构,它接收的参数,必须具有
迭代器属性
比如我们刚刚传进去的是一个数组,数组具有迭代器属性。可以被迭代换一个理解方式就是可以被遍历 - 否则报错:TypeError: number 5 is not iterable (cannot read property Symbol(Symbol.iterator))
const s2 = new Set([1,2,2])
const s3 = new Set(5) //报错
接下来,我们思考一个问题:如何把一个数组去重?
- 这种数据结构自身是否有去重方法
- 其他数据结构是否有这种方法能够去重,如果有,就想办法转成这种数据结构
- 手搓一个方法解决
- 根据我们刚刚了解到的set集合身上的特性:不存在重复项解题
const arr = [1,2,2,3,3,4,4,5,5,1]
const arr2 = [...new Set(arr)]
console.log(arr2)
思考2:如何把一个字符串去重? 字符串也是可以被迭代的,因此也可以作为参数传给set集合
const str = 'abcabc'
console.log([...new Set(str)].join(''));
set集合的遍历for of
我们提到了,set身上没有方法能够拿出他的某一个值,不能通过下标去取值,value方法只能取到全部的值
- 而for of方法是专门用来遍历具有
迭代器属性
的结构
const s2 = new Set([1,2,2])
for(let item of s2){
console.log()item
}
我们知道forEach
是专门用来遍历数组的,参数有item,index,arr,那如果是用来遍历set集合呢?
s.forEach((val,key)=>{
console.log(val,key)
})
WeakSet
WeakSet的创建
WeakSet的值,只能是对象和Symbol
let ws = new WeakSet()
ws.add({})
console.log(ws)
WeakSet 要点
- WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
举个例子
var a = 1
var obj = {n:2}
// xxx
var arr = [obj.n]
在这个例子中,当代码执行到第五行,垃圾回收机制就会去看,这个obj对象是否不再被使用了,如果不再被使用了,他会在一个时机给他回收掉,但是发现了第六行还有用到这个obj,因此不会被回收。
var a = 1
var obj = {n:2}
// xxx
// var arr = [obj.n]
var ws = new WeakSet(obj)
但是如果第六行改成了第七行,垃圾回收机制就不会发现他还需要被使用,代码执行到第五行时,这个obj就叫做后续不需要使用了,可以回收了。这就是所谓的垃圾回收机制不考虑 WeakSet 对该对象的引用
global.gc() 垃圾回收机制
global.gc(); // 手动执行垃圾回收
console.log(processs.memoryUsage()); // 2.6M 干净情况下2.6M
let obj = {name: '张三',age:new Array(5*1024*1024)} // 放入东西,内存会增长
let ws = new WeakSet()
ws.add(obj)
global.gc(); // 手动执行垃圾回收
console.log(processs.memoryUsage()); // 4.4M
- 可以看见第一次我们手动清理一次,干净情况下2.6M,加入obj后,内存占用情况变成4.4M
- 如果我们把一个对象
赋值为null
,就是告诉垃圾回收机制可以来清理了
global.gc(); // 手动执行垃圾回收
console.log(processs.memoryUsage()); // 2.6M 干净情况下2.6M
let obj = {name: '张三',age:new Array(5*1024*1024)} // 放入东西,内存会增长
let ws = new WeakSet()
ws.add(obj)
obj = null;
global.gc(); // 手动执行垃圾回收
console.log(processs.memoryUsage()); // 2.5M
- 当我们赋值为null并手动清理时,内存变回来了,一点点误差可以忽略,每一次都不一样很正常
- 如果我们不把对象赋值为null,那么只要当一个对象被使用完了,垃圾回收机制就会在一个时机进行回收,但是这个时机不受人类控制,我们不能确定他会在什么时候进行回收
我们回到对WeakSet要点的总结:
- WeakSet是弱引用
- 一个对象存在了其他的结构中,当后续存在其他对象引用这个对象,那么这个对象不会被GC回收
- 一个对象obj存在了其他结构中,当后续只存在weakSet对他的引用,该对象的内存依然会被回收
- 由于这个特点,WeakSet的成员是不适合引用的,因为它随时会消失,另外,由于WeakSet内部有多少个成员取决于垃圾回收机制有没有运行运行前后很可能成员数量是不一样的,而垃圾回收机制何时运行是不可预测的,因此ES6规定WeakSet不可遍历
Map
一种新的对象,可以用来弥补obj身上的一些不足,例如:
const n = 123;
const obj1 = {
a: 1,
n: 2
}
- 我们知道,对象中的属性,这里的n就是字符串n,打印出来obj1,就是属性a和n
- 如果要拿n的值作为属性
const n = 123;
const obj1 = {
a: 1,
[n]: 2
}
- 这样obj1中就是字符串a值为1,字符串123,值为2,属性就是字符串,如果不是字符串也会被转成字符串
const n = 123
consr el = document.getElementById('btn')
const obj = {
a:1,
[el]:2
}
那如果我们想用这个dom结构来做key,在这种场景下,dom结构就会变成一个字符串,由此,map就孕育而生了
const m = new Map();
const o = { age: 18 }
m.set(o, [1, 2, 3])
console.log(m); // Map(1) { { age: 18 } => [ 1, 2, 3 ] }
- 创建一个map对象,用对象来做key,数组来做value。
- 弥补了传统对象只能用字符串做key的缺陷。
map的一些方法
m.set(key,value)
,增加键值对m.get(key)
,取键对key的值m.delete(key)
,移除键值对m.has(o)
,判断是否存在键值对m.size
,map有几个值m.keys()
,有哪些keym.values()
,有哪些valuem.entries()
,拿到键值对,用数组包裹
WeakMap
set和WeakSet类似,map和WeakMap也类似,也是用于生成键值对的集合。
- 区别:WeakMap只接收对象和Symbol值作为键名
- 要点:它的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。
这些都和WeakSet类似不再过多论述
小结
我们论述了set、map,以及WeakSet和WeakMap,前两个是强引用,后两个是弱引用。set是不能有重复值的,而且它的下标也是默认自动生成的,map弥补了传统对象中只能用字符串来当key的不足,而WeakSet和WeakMap使用起来大差不差,只不过他们是弱引用,还有他们只能存对象和Symbol值。
转载自:https://juejin.cn/post/7380200984058118170