Set、Map、WeakSet、WeakMap
如果要用一句来形容,咱们能够说
Set是一种叫做汇合的数据结构,Map是一种叫做字典的数据结构
那什么是汇合?什么又是字典呢?
- 汇合
汇合,是由一堆无序的、相关联的,且不反复的内存构造【数学中称为元素】组成的组合
- 字典
字典(dictionary)是一些元素的汇合。每个元素有一个称作key 的域,不同元素的key 各不相同
那么汇合和字典又有什么区别呢?
- 共同点:汇合、字典都能够存储不反复的值
- 不同点:汇合是以[值,值]的模式存储元素,字典是以[键,值]的模式存储
背景
大多数支流编程语言都有多种内置的数据汇合。例如Python
领有列表(list
)、元组(tuple
)和字典(dictionary
),Java有列表(list
)、汇合(set
)、队列(queue
)
然而 JavaScript
直到ES6
的公布之前,只领有数组(array
)和对象(object
)这两个内建的数据汇合
在 ES6
之前,咱们通常应用内置的 Object
模仿Map
然而这样模仿进去的map
会有一些缺点,如下:
Object
的属性键是String
或Symbol
,这限度了它们作为不同数据类型的键/值对汇合的能力Object
不是设计来作为一种数据汇合,因而没有间接无效的办法来确定对象具备多少属性
Set
定义:Set
对象容许你存储任何类型的惟一值,无论是原始值或者是对象援用,Set
对象是值的汇合,你能够依照插入的程序迭代它的元素。Set
中的元素只会呈现一次,即Set
中的元素是惟一的
Set
自身是一个构造函数,用来生成 Set
数据结构
根本应用
- 语法
new Set([iterable])
接管一个数组(或者具备 iterable 接口的其余数据结构), 返回一个新的Set
对象
const set = new Set([1,2,1,2])console.log(set) // {1,2}
下面代码能够看出 Set
是能够去除数组中的反复元素
属性及办法
属性
- size: 返回汇合中所蕴含的元素的数量
console.log(new Set([1,2,1,2]).size) // 2
操作方法
- add(value): 向汇合中增加一个新的项
- delete(value): 从汇合中删除一个值
- has(value): 如果值在汇合中存在,返回ture, 否则返回false
- clear(): 移除汇合中的所有项
let set = new Set()set.add(1)set.add(2)set.add(2)set.add(3)console.log(set) // {1,2,3}set.has(2) // trueset.delete(2) set.has(2) // falseset.clear()
遍历办法
- keys(): 返回键名的遍历器
- values(): 返回键值的遍历器
- entries(): 返回键值对的遍历器
- forEach(): 应用回调函数遍历每个成员
let set = new Set([1,2,3,4])// 因为set只有键值,没有键名,所以keys() values()行为完全一致console.log(Array.from(set.keys())) // [1,2,3,4]console.log(Array.from(set.values())) // [1,2,3,4]console.log(Array.from(set.entries())) // [[1,1],[2,2],[3,3],[4,4]]set.forEach((item) => { console.log(item)}) // 1,2,3,4
利用场景
因为 Set
构造的值是惟一的,咱们能够很轻松的实现以下
// 数组去重let arr = [1, 1, 2, 3];let unique = [... new Set(arr)];let a = new Set([1, 2, 3]);let b = new Set([4, 3, 2]); // 并集let union = [...new Set([...a, ...b])]; // [1,2,3,4] // 交加let intersect = [...new Set([...a].filter(x => b.has(x)))]; [2,3] // 差集let difference = Array.from(new Set([...a].filter(x => !b.has(x)))); [1]
WeakSet
WeakSet 对象是一些对象值的汇合, 并且其中的每个对象值都只能呈现一次。在WeakSet的汇合中是惟一的
WeakSet
的呈现次要解决弱援用对象存储的场景, 其构造与Set
相似
与Set
的区别
- 与Set相比,WeakSet 只能是对象的汇合,而不能是任何类型的任意值
- WeakSet汇合中对象的援用为弱援用。 如果没有其余的对WeakSet中对象的援用,那么这些对象会被当成垃圾回收掉。 这也意味着WeakSet中没有存储以后对象的列表。 正因为这样,WeakSet 是不可枚举的
WeakSet
的属性跟操作方法与 Set
统一,不同的是 WeakSet
没有遍历办法,因为其成员都是弱援用,弱援用随时都会隐没,遍历机制无奈保障成员的存在
下面始终有提到弱援用,那弱援用到底是指什么呢?
弱援用是指不能确保其援用的对象不会被垃圾回收器回收的援用,换句话说就是可能在任意工夫被回收
Map
Map 对象保留键值对,并且可能记住键的原始插入程序。任何值(对象或者原始值) 都能够作为一个键或一个值。一个Map对象在迭代时会依据对象中元素的插入程序来进行 — 一个 for...of 循环在每次迭代后会返回一个模式为[key,value]的数组
根本应用
- 语法
new Map([iterable])
Iterable
能够是一个数组或者其余 iterable
对象,其元素为键值对(两个元素的数组,例如: [[ 1, 'one' ],[ 2, 'two' ]])。 每个键值对都会增加到新的 Map
let map = new Map()map.set('name', 'vuejs.cn');console.log(map.get('name'))
属性及办法
根本跟 Set
相似,同样具备如下办法
属性
- size: 返回 Map 构造的元素总数
let map = new Map()map.set('name', 'vuejs.cn');console.log(map.size) // 1console.log(new Map([['name','vue3js.cn'], ['age','18']]).size) // 2
操作方法
- set(key, value): 向 Map 中退出或更新键值对
- get(key): 读取 key 对用的值,如果没有,返回 undefined
- has(key): 某个键是否在 Map 对象中,在返回 true 否则返回 false
- delete(key): 删除某个键,返回 true, 如果删除失败返回 false
- clear(): 删除所有元素
let map = new Map()map.set('name','vue3js.cn')map.set('age','18')console.log(map) // Map {"name" => "vuejs.cn", "age" => "18"}map.get('name') // vue3js.cn map.has('name') // truemap.delete('name') map.has(name) // falsemap.clear() // Map {}
遍历办法
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回所有成员的遍历器
- forEach():遍历 Map 的所有成员
let map = new Map()map.set('name','vue3js.cn')map.set('age','18')console.log([...map.keys()]) // ["name", "age"]console.log([...map.values()]) // ["vue3js.cn", "18"]console.log([...map.entries()]) // [['name','vue3js.cn'], ['age','18']]// name vuejs.cn// age 18map.forEach((value, key) => { console.log(key, value)})
利用场景
Map
会保留所有元素的程序, 是在基于可迭代的根底上构建的,如果思考到元素迭代或程序保留或键值类型丰盛的状况下都能够应用,上面摘抄自 vue3
源码中依赖收集的外围实现
let depsMap = targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let dep = depsMap.get(key) if (!dep) { depsMap.set(key, (dep = new Set())) } if (!dep.has(activeEffect)) { dep.add(activeEffect) activeEffect.deps.push(dep) ... }
WeakMap
WeakMap 对象是一组键/值对的汇合,其中的键是弱援用的。其键必须是对象,而值能够是任意的
与Map
的区别
- Map 的键能够是任意类型,WeakMap 的键只能是对象类型
- WeakMap 键名所指向的对象,不计入垃圾回收机制
WeakMap
的属性跟操作方法与 Map
统一,同 WeakSet
一样,因为是弱援用,所以 WeakSet
也没有遍历办法
类型的转换
Map
转为Array
// 解构const map = new Map([[1, 1], [2, 2], [3, 3]])console.log([...map]) // [[1, 1], [2, 2], [3, 3]]// Array.from()const map = new Map([[1, 1], [2, 2], [3, 3]])console.log(Array.from(map)) // [[1, 1], [2, 2], [3, 3]]
Array
转为Map
const map = new Map([[1, 1], [2, 2], [3, 3]])console.log(map) // Map {1 => 1, 2 => 2, 3 => 3}
Map
转为Object
// 非字符串键名会被转换为字符串function mapToObj(map) { let obj = Object.create(null) for (let [key, value] of map) { obj[key] = value } return obj}const map = new Map().set('name', 'vue3js.cn').set('age', '18')mapToObj(map) // {name: "vue3js.cn", age: "18"}
Object
转为Map
let obj = {"a":1, "b":2};let map = new Map(Object.entries(obj))
总结
- Set、Map、WeakSet、WeakMap、都是一种汇合的数据结构
- Set、WeakSet 是[值,值]的汇合,且具备唯一性
- Map 和 WeakMap 是一种[键,值]的汇合,Map 的键能够是任意类型,WeakMap 的键只能是对象类型
- Set 和 Map 有遍历办法,WeakSet 和 WeakMap 属于弱援用不可遍历
参考
- https://zh.wikipedia.org/wiki/%E5%BC%B1%E5%BC%95%E7%94%A8
- https://developer.mozilla.org/
- https://es6.ruanyifeng.com/