前言
🙋 知其然,更知其所以然,举一反三,融会贯通
最近一段时间在看vue3核心实现相关的书籍,在收集和触发副作用函数代码里有关于Set,Map和weakMap的知识点,并且有讲解到他们的优点和作用,其实很早之前对它们就有所了解,但是在实际的开发过程中用到的并不多,知道的还是一知半解,今天再来温顾一下。
Map
Map是ES6中一种新的数据结构,与Object类似,是一组键值对的集合,基本用法如下:
const map = new Map()
也可以创建一个带初始值的集合
const map = new Map([
['title', 'hello world'],
['content', 'this is a code life']
[{title: 'hi'}, 'tom']
])
常用方法
set
const map = new Map()
map.set('title', 'hello world')
get
通过属性获取对应的值
const map = new Map([
['title', 'hello world'],
['content', 'this is a code life']
])
console.log(map.get('title'))
has
判断map对象中是否有某个属性值,返回boolean类型
const map = new Map([
['title', 'hello world'],
['content', 'this is a code life']
])
console.log(map.has('title')) // hello world
size
获取对象键值对的个数
const map = new Map([
['title', 'hello world'],
['content', 'this is a code life']
])
console.log(map.size())) // 2
delete
通过属性进行删除
const map = new Map([
['title', 'hello world'],
['content', 'this is a code life']
])
console.log(map.get('title'))) // hello world
clear
清除所有键值对
const map = new Map([
['title', 'hello world'],
['content', 'this is a code life']
])
map.clear()
console.log(map.get('title'))) // undefiend
Map和Object的区别
创建实例
map对象的创建只有一个方式
const map = new Map([
['title', 'hello']
])
object对象的创建有多种方式
const obj = {}
const obj2 = new Object()
const obj3 = Object.create(null)
继承
普通的object对象,直接继承Object的原型对象
new Map的实例对象继承Map的原型对象,Map继承Object的原型对象,会多一层继承
迭代
new Map()的对象可以通过for...of进行迭代循环
Object的实例对象不能通过for...of进行迭代,但是可以同通过for...in遍历枚举所有的key值
判断一个对象是否可以迭代的方法是其属性中是否包括symbol.iterator
const map = new Map([
['title', 'hello world'],
])
const obj = { "title": "hello world" }
console.log(obj[Symbol.iterator]) // false
console.log(map[Symbol.iterator]) // ƒ entries() { [native code] }
key值
Object实例对象的键只能是string和symbol类型,如果写成number类型,js会自动转化为string,如果写成引用类型会直接报错。
Map实例对象的键可以是任何类型,包括引用类型
const map = new Map([
["title", "hello world"],
[{'content': 123}, "hello content"]
])
key的有序和无序
Map和Object的实例对象都是一组键值对的组合,但它们是有区别的:
我们都知道object中的key值是无序排序的,是不可靠的。
但map对象的key是有序排列的,它会根据key值添加的时间进行排序,先添加的排在前面
Set
ES6中新增的集合数据结构,其Api与map基本一样,没有set和get,有add
基本使用
const arr = new Set([1,2])
arr.add(3).add(4).add(5)
console.log(arr.has(3)) // true
arr.size() // 4
arr.delete(3)
arr.clear()
查看它的数据结构,与数组是比较类似,都是存储一个数据集合,它与数组的区别是存储的值不能重复,必须是唯一的值,另外它的原型属性里面也没有与数组相同的其他方法,我们通常称它为类数组。
如果我们想像普通数组一样操作Set集合,就需要先把它进行转化,有两种方式: Array.from和扩展运算符
const arr = new Set([1,2,3,4,5])
arr.add(1).add(4)
const newArr = Array.from(arr) // 转化为类数组
// const newArr = [...arr]
newArr.push(6)
console.log(newArr)
使用场景
最常见的场景就是用来对数组去重
const arr = [1,2,3,4,5,6,4,3]
const newArr = new Set(arr)
console.log(newArr)
WeakMap
WeakMap与Map类似,也是用来生成键值对集合。
- WeakMap只接受对象作为键名,不接受其他类型的值作为键名
- WeakMap键名是弱引用,键值可以是任意的,键名所指的对象可以被垃圾回收机制回收
- WeakMap实例不可被迭代,因此不能用
for...of方法,其只有get,set,has,delete方法
WeakSet
WeakSet与Set类似,用法基本一样,但其存储的值只能是数组或类数组的对象,如果通过add方法添加其他类型的值就会报错。
const arr = new WeakSet([[1],[2,3]])
arr.set(3) // Uncaught TypeError: Invalid value used in weak set
- WeakSet成员都是弱引用的,可以被垃圾回收机制回收
- WeakSet实例不可被迭代,因此不能用
for...of方法 - WeakSet没有size方法