Set和Map

阅读 1.5k
标签: JavaScript

ES6之前,JavaScript只有一种集合类型,那就是数组。和其他语言相比,这实在是显得寒酸了些。虽然对象常被作为键值对的集合形式来使用,但对象会受限于其自身的设计和特性,为了统一和补充集合,ES6标准诞生了两种新的集合:Set和Map。

Set

Set集合是一种列表,其最特殊的地方在于: 其中的元素是没有重复的。来看一个小例子:

javascript
let set = new Set()
set.add(5)
set.add(5)
set.add('5')
set.has(5) // true
set.delete(5)
set.has(5) // false
console.log(set.size) // 1
set.clear()
console.log(set.size) // 0

上面代码中,先是创建了一个空的set集合,再通过add()方法添加了一些元素,随后,又删除了元素5,最终,通过clear()方法彻底清空了set集合。

Set和数组

对于Set而言,可以通过forEach()来遍历其中的数据,但是它无法像数组一样,通过索引来访问其中的元素,对于使用Set的场景而言,我们一般不关心其中数据的顺序,我们更关心的是其自身去重的功能。在某些请下,我们需要对Set和数组之间进行转换,比如,对数组去重:

javascript
let set = new Set([1, 2, 3, 4, 5, 5, 5])
let arr = [...set]

从上面代码可以看出,数组要转换为Set,只需要通过Set构造函数即可,就会得到一个没有重复值的Set集合,最后,当然还需要再从Set集合转换为数组类型,通过展开运算符可以将Set中的值逐一展开,然后放入数组中即可。

WeakSet

WeakSet是什么东西呢?既然有了Set,为啥还需要搞出这个?我们先来看一个场景:

javascript
let set = new Set()
let dom = { id: 'app', type: 'div' }
set.add(dom)
dom = null // 希望回收这个DOM节点
// 依旧可以获得希望被垃圾回收的dom对象的引用
let reKey = [...set][0]
console.log(reKey.type) // "div"

上面代码中,有一个dom节点对象被添加到了一个Set集合中,当不再需要的时候,我们希望垃圾回收器能够将其回收掉,所以将dom赋值为null,但是很遗憾,最终这个dom值并没有被回收掉,这导致了内存泄露。所以,WeakSet就是为了解决这个问题的。

javascript
let set2 = new WeakSet()
let dom = { id: 'app', type: 'div' }
set2.add(dom)
dom = null

当上面代码中dom被赋值为null后,set2中的dom引用也会被自动移除,再次访问set中的那个dom元素的属性就会报错(因为其已经被移除了)。

虽然WeakSet和Set有很多相同之处,但是,他们也有一些差别:

  • 在WeakSet的实例中,add()方法只能接收对象,其他类型(字符串,数字,boolean等)都会报错
  • WeakSet不可迭代,无法使用for-of循环
  • WeakSet不支持forEach()方法
  • WeakSet不支持size属性

WeakSet看上去有点“弱”,这是对的,因为一般情况,都会选择使用Set,而这个WeakSet仅用在特殊的场景,它能自动移除希望被垃圾回收器回收的对象,当你需要跟踪对象,并防止内存泄露的场景下,才选择WeakSet。

Map

Map是一种存储键值对的列表,它和对象很像,因为对象也是键值对的形式,但是它们之间还是有很多差别的,对象中的属性总会被强制转换为字符串类型,比如对象中:

javascript
let obj = {}
key1 = 5
key2 = '5'
obj[key1] = 100
obj[key2] = 200
console.log(obj) // {5: 200}

而在Map中:

javascript
let map = new Map()
map.set(5, 'number')
map.set('5', 'string')
console.log(map)
console.log(map.get(5)) // 'number'

键5(数字)和键‘5’(字符串)是两个不同的键,不会像对象的属性一样,会被强制转换。

Map中支持的方法和Set类似,有如下几种常见方法:

  • set(key, value):设置指定的键值对
  • get(key):获得指定键的值
  • has(key):检测指定的键名是否存在
  • delete(key):删除指定的键名以及对应的值
  • clear():移除Map中的所有键值对

注意:Set集合用add()来添加值,而Map集合用set()来设置键值对。

可以向Map构造函数传入数组来初始化一个Map集合:

javascript
let arr = [
['name', 'foo'],
['age', 30]
]
let map2 = new Map(arr)
console.log(map2.get('age')) // 30

注意,其需要传入一个二维数组,且内部的子数组中包含一个键和一个值。

参考

  • 深入理解ES6 / Nicholas C. Zakas

最后编辑于: 2022-06-26

评论(0条)

(必填)
复制成功