前言
相信大家在刷算法题时,应该都碰到过Map 数据结构,它可以解决一些与键值对相关的问题,例如快速查找、存储关联信息等。可是很多人对这两个数据结构并没有那么熟悉,导致许多应用场景或者面试的过程中无法理解它们的真正含义,那么本文将带领大家彻底搞懂Set和Map。
Set
定义方法 :new Set()
,通过Set构造函数生成Set数据结构,且接受一个数组作为参数
1.是一种 key和value相等的特殊对象
vbscript
let set = new Set([1,2,3,4])
console.log(set); // Set(4) { 1, 2, 3, 4 }
很明显,打印出的set对象{1, 2, 3, 4}
很特殊,没有键,只有值,可以推测Set实例对象是一个key和value相等的特殊对象。我们可以把它理解成用于存储唯一值的集合。 我们再去浏览器上看看Set对象的真面目:
怎么样是不是非常像数组,所以Set也跟类数组很类似,所以很多小伙伴会觉得访问Set中的元素和数组类似,通过下标访问即可,可事实并非如此!
当你打印Set[0]
时,你会发现结果是undefined。说明Set中的元素是不能通过下标访问的,一定要记住!如何访问请继续往下读。
2.set 对象中的值是唯一的
vbscript
let set = new Set([1,2,2,3,4])
console.log(set); // Set(4) { 1, 2, 3, 4 }
只要是定义在Set对象中的值,一定不存在重复的现象。
所以通过这个特性,Set也经常用于数组的去重操作:
javascript
var arr = [1,2,1,1,'1']
var unique = (arr) => Array.from(new Set(arr))
console.log(unique(arr)); //[1,2,'1']
Array.from()
方法可以将 Set 结构转为数组。箭头函数返回 Array.from(new Set(arr))
或者 [...new Set(arr)]
都没问题。扩展运算符(...
)内部使用for...of
循环,所以也可以用于 Set 结构。
3.Set 实例的属性和方法
属性: Set.size
:返回Set
实例的成员总数,与数组身上的length
类似
常用方法: add、clear、delete、has
csharp
let set = new Set([1,2,2,3,4])
set.add(1) //添加某个值,返回 Set 结构本身。
set.clear() // 清除所有元素,没有返回值
set.delete(1) //true 删除一个元素,返回一个布尔值,表示删除是否成功。
set.has(1) //true 判断Set是否存在该值,返回布尔值
4. Set遍历、具有迭代器(iterator)属性
Set实例具有迭代器 属性,这也意味着Set实例可被for..of
遍历,但是我们一般给Set实例的keys
方法、values
方法、entries
方法返回的值遍历:
csharp
let set = new Set([1,2,3,4])
for (let i of set.keys()){ //返回所有的键名
console.log(i); // 1 2 3 4
}
for (let i of set.values()){ //返回所有的键值
console.log(i); // 1 2 3 4
}
for (let i of set.entries()){ //键的名和值均返回,输出为一个数组
console.log(i); // [1,1] [2,2] [3,3] [4,4]
}
当然你直接给Set实例遍历也是可以的。
Set实例也可以使用forEach方法遍历:
javascript
let set = new Set([1,2,3,4])
set.forEach(el => {
console.log(el); // 1 2 3 4
})
Map
定义方法: 定义方法 :new Map()
,通过Map构造函数生成Map数据结构,且接受一个二维数组数组作为参数,或者说接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
ini
let map = new Map([
['name', '张三']
]);
1. 可以用任意数据类型做key的特殊对象
传统的对象中的key只能为字符串类型,新增的Map实例中的key可以为任意类型。
但是我们要注意,如果将引用类型做为key的话,有几个小坑:
arduino
let map = new Map([
['name', '张三']
]);
map.set({a: 1}, 2) // 添加元素
map.get({a :1}) // 访问元素
那么这里的get
方法能访问到值吗?答案是不能,原因很简单,这里set
中的{a: 1}
与get
中的{a: 1}
是不一样的!两者虽然值相同,但是对于引用类型的值来说,引用地址也要一样。
解决方法:用一个变量将对象存下来。
csharp
let map = new Map([
['name', '张三']
]);
let obj = {a: 1}
map.set(obj, 2)
map.get(obj) // 2
2. Map实例的属性和方法
属性: size
属性返回 Map 结构的成员总数。
常用方法:set、get、delete、clear、has
csharp
let map = new Map()
set.set(1,2)
set.get(1) //2
set.delete(1) //true
set.has(1) //true
set.clear()
set
方法设置键名key
对应的键值为value
,然后返回整个 Map 结构。如果key
已经有值,则键值会被更新,否则就新生成该键。get
方法读取key
对应的键值,如果找不到key
,返回undefined
。has
方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。delete()
方法删除某个键,返回true
。如果删除失败,返回false
。clear()
方法清除所有成员,没有返回值。
3. Map遍历、具有迭代器(iterator)属性
Map实例也具有迭代器属性,foreach和for...of遍历均可:
arduino
//foreach
map.forEach((value,key,map) => {
console.log(value,key,map);
})
2.for...of
for(let i of map){
console.log(i);
}
聊聊WeakSet、WeakMap
因为WeakSet、WeakMap的特殊之处类似,所以我就用WeakSet作为代表。
WeakSet 结构与 Set 类似,也是不重复的值的集合。我们只需知道它与 Set 有两个区别。
1.WeakSet 的成员
WeakSet 的成员只能是对象和 Symbol 值,而不能是其他类型的值。
csharp
const ws = new WeakSet()
ws.add(1) //报错
ws.add(Symbol()) // 不报错
2.WeakSet 中的对象都是弱引用
简单来说,一个对象被WeakSet所引用,在垃圾回收机制的眼中,该对象是没有被引用的。也就是说当其他对象都不再引用该对象时,只要垃圾回收机制一生效,该对象所占据的内存空间就会被销毁。
javascript
let obj = { name: '德玛西亚'}
let ws = new WeakSet()
ws.add(obj) //不考虑,obj直接销毁
obj = null //相当于手动销毁obj
console.log(ws) //空对象
相信很多小伙伴都尝试了一下上面的代码吧,但是打印结果令人大跌眼镜,ws
依旧保存着obj
。那么这个现象是非常正常的,因为垃圾回收机制不是可控的,可能我们打印的时候垃圾回收机制还未生效罢了,所以ws
理论上就是一个空对象。
最后
希望本文对大家能有帮助!
文章参考: