一文掌握Symbol、Map、weakMap、Set

117 阅读3分钟

Symbol

  • JS内置的原始数据类型
  • 每个Symbol都不相同
const sym1 = symbol()
const sym2 = symbol('foo')
const sym3 = symbol('foo')
console.log(sym === sym3) // false
let obj = {[sym1]: 'a'}
obj[sym2] = 'b'
console.log(obj[sym1]) // 'a'

Symbol 常用于放在对象中使用。比如说你写了一个对象,里面有一个key,你不想其他的使用者把他覆盖了,就可以使用symbol。


Set

  • Set对象是值的集合,可以按照插入的顺序迭代它的元素。Set中的元素是唯一的。

用法:

  • let set = new Set()
  • set.add(val)
  • set.delete(val)
  • set.has(val)
  • set.size
  • set.clear()
  • set.forEach(callback)
  • [...set]
let set = new Set()
set.add('yellow')
set.add('red')
console.log( set.has('red') )
set.delete('red')
console.log( set )
console.log( set.size )
set.add({a:1})
set.forEach(v => {
 console.log(v)
})
console.log( new Set('我是谁') ) // 把字符一个个分割,放到集合里去
let arr = [3, 4, 4, 1, 5, 5]
let result = [...new Set(arr)] //数组去重
console.log(result)

Map

  • Map对象是键值对的集合。Map中的一个键只能出现一次。任何值都可以作为Map的键和值
Object和Map有什么区别
  • Map的键可以是任意值,Object只能是字符串和Symbol
  • Map的键是有序的,Object是无序的
  • Map可以获取size,Object需要自己计算
  • Map性能更好
  • Map是可迭代的可用for...of,Object是不可迭代的,可用for...in遍历
// 于Set的用法基本一致
let map = new Map()
map.set('name', 'jirengu')
map.set(1, 100)
let obj = {a: 1}
map.set(obj, 2)
console.log( map.get('name') )
console.log( map.get(obj) )
map.delete('name')
map.forEach((val, key)=> {
 console.log(val, key)
})
for(let [key, value] of map) {
 console.log(key, value)
}
console.log(map.size

WeakMap

  • WeakMap对象是一组键/值对的集合,其中的键是弱引用。其键必须是对象,而值可以是任意的。用法跟map基本一致,只不过WeakMap不可以遍历。
  • 如果key是引用类型推荐使用WeakMap
啥时候该用 WeakMap

再JS中,map API 可以通过四个API的方法共用两个数组(一个存放键,一个存放值)来实现。给map设置值时会同时将键和值添加到这两个数组的末尾。当你从map里取值时,需要遍历所有的键,然后使用索引从存储值得数组中检索出相应得值。

但这样得实现会有两个很大得缺点:

  1. 因为这两个操作需要遍历整个数组进行匹配,需要得时间会更多。
  2. 另外一个缺点是会导致内存泄露,因为数组会一直引用每个键和值。这使得垃圾回收机制不能回收处理它们,即使没有任何引用存在了。

相比之下 WeakMap 持有的是对每个键对象的“弱引用”,这意味着再没有其他引用存在时垃圾回收能正确进行。WeakMap的解构是有效的,其用于映射的key只有再没有被回收时才是有效的。

正由于这样的引用,WeakMap的key是不可枚举的。如果key是可枚举的话,其列表将会受到垃圾回收机制的影响,从而得到不确定的结果,如果你想要这种类型对象的key值得列表,你应该使用Map。