案头见蠹鱼,犹胜凡俦侣。这篇文章主要讲述浅析 Map 和 WeakMap 区别以及使用场景相关的知识,希望能为你提供帮助。
希望这一篇文章能让你对 Map
有更好的理解,或者能够帮你理解 Map
和 WeakMap
这篇文章会先从Map
再到WeakMap
一、为什么是 Map ?
1. 传统对象结构
Map
本质上是一个键值对的集合。和传统对象结构相比,传统的对象只能用字符串作为键名,这就在使用上造成了很大的限制了。这也是新增 Map
的原因之一。
const data = https://www.songbingjia.com/android/{};
// element 为节点对象
const element = document.querySelector(".node");
console.log(element);
// 输出 div.node 对象
// 将对象转化成字符串输出 [object htmlDivElement]
console.log(element.toString());
// 用点操作符不能有空格,所以采用中括号的形式给对象赋值
data[element] = \'objectData\'
// 输出 objectData,说明在对象中存在[object HTMLDivElement]键名
console.log(data[\'[object HTMLDivElement]\']);
在上面的代码中,我们创建了一个对象并将一个节点对象作为了它的键名,并进行了代码测试,首先验证了获取到的
element
节点为一个对象,再确定了经过toString
方法转化后的结果,以这个值为键名成功的输出了value
值objectData
文章图片
通过上面的测试,确定了传统对象的键名会通过
toString
方法转化为字符串类型2. Map 结构
Map
类似于对象,但是键名不限于字符串,可以说Object
结构提供键-值对应,Map
结构提供值-值对应因此其实采用map
结构会优于传统对象// 1. 通过new Map来创建dataMap容器
const dataMap = new Map();
// 2. 获取节点对象,作为测试数据
const element = document.querySelector(".node");
// 3. 通过 set 方法给 dataMap 中指定键和对应的值
dataMap.set(element,\'objectData\');
// 4. 通过 get 来从 dataMap 中获取键名对应的值
console.log(dataMap.get(element));
// 5. 揭开面目
console.log(dataMap);
从上面的代码中,我们可以清楚的看到,第8行代码获取值时直接传入了
element
对象,可以成功的获取到对应的值,在最后打印
dataMap
时更是验证了上诉说法文章图片
成功的将对象作为了键名,弥补了传统对象的不足
3. Map 的特点
- Map 默认情况下不包含任何键,所有键都是自己添加进去的。不同于 Object 原型链上有一些默认的键。
- Map 的键可以是任意类型数据,就连函数都可以。
- 【浅析 Map 和 WeakMap 区别以及使用场景】Map 的键值对个数可以轻易通过
size
属性获取,Object 需要手动计算。
- Map 在频繁增删键值对的场景下性能要比 Object 好。
- 要添加的键值名和 Object 上的默认键值名冲突,又不想改名时,用 Map
- 需要 String 和 Symbol 以外的数据类型做键值时,用 Map
- 键值对很多,有需要计算数量时,用 Map
- 需要频繁增删键值对时,用 Map
Map
的个别API,接下来简单说说1. set
set
方法设置键名key
对应的键值为value
,然后会返回整个Map
结构,如果设置的key
已经存在,则会更新value
值,否则会新生成该键文章图片
也可以采用链式写法设置多组数据
文章图片
成功输出如下:
文章图片
2. get
通过
get
方法读取key
对应的键值,如果传入的键值不存在,则会返回undefined
文章图片
控制台成功输出
ljc
3. has
判断传入的键是否存在当前
Map
对象中,该方法返回一个布尔值文章图片
在上面的代码中,存在
name
为true
,不存在sex
返回false
4. delete
删除传入的键,返回
true
,如果删除失败,则返回false
文章图片
5. clear
清除所有成员,没有返回值
文章图片
clear
前后结果对比,注意clear
没有返回值!文章图片
三、遍历方法可以采用
for...of
循环和forEach
两种方法。由于Map
实例会维护键值对的插入顺序,因此可以根据插入顺序进行遍历采用for...of
keys()
:返回键名的遍历器values()
:返回键值的遍历器entries()
:返回键值对的遍历器forEach()
:使用回调函数遍历每个成员
Map
实例中有一个迭代器,能以插入顺序生成[key,value]
形式的数据。我们可以通过
entries
方法来获得这个迭代器,从而利用for...of
进行遍历操作文章图片
文章图片
也可以采用如下进行遍历,每次
item
获取到一个数组文章图片
又因为
entries
是默认的迭代器,所以可以直接对Map
实例使用扩展操作或者直接采用map
文章图片
采用扩展操作
文章图片
map.values()可以采用遍历
map.values()
的方式来遍历map
容器的属性值文章图片
map.keys()可以采用
map.keys()
来遍历键名文章图片
采用 forEach() 回调遍历
文章图片
通过回调的方式遍历
map
四、Map 类型转化几种与
map
相互类型转化的方法Map 转为数组通过扩展运算符实现
let map = new Map()
let arr = [...map]
数组转为 Map
let map = new Map(arr)
Map 转为对象通过遍历利用
set
将键值对加入对象中let obj = {}
for (let [k, v] of map) {
obj[k] = v
}
对象转为 Map
for( let k of Object.keys(obj)){
map.set(k,obj[k])
}
五、什么是 WeakMap ?总所周知,
WeakMap
是 ES6 中新增的一种集合类型,叫做“弱映射”。它和Map
是兄弟关系,与Map
的区别就在于这个弱字,API 还是Map
的那套(只有set
get
has
delete
)那它真正是什么意思呢?
那为什么要有 WeakMap 呢?它解决了什么问题呢?这些问题后面都会讲到
六、WeakMap 的特性我们先从 WeakMap 的特性讲起
1. WeakMap 只能将对象作为键名
- 只接受对象作为键名(
null
除外),不接受其他类型的值作为键名
文章图片
文章图片
正常添加
文章图片
2. WeakMap 的键名引用的对象是弱引用
这里懵了挺久的,但是这是
WeakMap
结构的关键所在要想读懂这句话,不容易,我们需要先知道强引用和弱引用
2.1 什么是强引用?我们先来看看强引用,这是阮一峰老师书上的例子
文章图片
在上面的代码中,
e1
和e2
是两个对象,通过arr
数组对这两个对象添加一些文字说明。但是这样就形成了arr
对e1
和e2
的引用,而这种引用又是强引用。它的区别就体现在。当我们不再需要这两个对象时,我们必须手动的删除这个引用,解除arr
都两个对象的引用关系,否则垃圾回收机制不会释放e1
和e2
占用的内存。因为,arr
仍然存在着对对象的引用!文章图片
麻烦的操作势必会造成问题,当忘记了手动删除引用,就会造成内存泄漏
2.2 什么是弱引用?对于弱引用,百度百科给出的答案:
也就是说如果我们能这样创建一个弱引用的对象
//假设
let obj = new WeakObject()
我们就可以静静的等待垃圾车来把它拖走了,
obj
所引用的对象就会被回收如果还没有理解的话,我们再来看看
2.3 弱引用和强引用图解从1套代码结合两张图来理解
对于强引用
const myMap = new Map()
let my = {
name: "ljc",
sex: "男"
}
myMap.set(my, \'info\');
console.log(myMap);
文章图片
对于弱引用
const myMap = new WeakMap()
let my = {
name: "ljc",
sex: "男"
}
myMap.set(my, \'info\');
console.log(myMap);
文章图片
图一中的数据被
my
和myMap
实例对象所引用,引用计数为 2,图2中建立了myMap
对my
所引用的对象的弱引用,引用计数为 1在上面我们谈到强引用数据被删除时,需要手动解除引用,而弱引用则可以等待垃圾回收机制自动清除
弱引用与垃圾回收
文章图片
当执行
my = null
时会解除my
对原数据的引用,而myMap
实例对象对my
所引用对象是弱引用关系,该数据的引用计数为 0 ,程序垃圾回收机制在执行时会将引用对象回收。而如果时强引用关系则引用计数为 1 ,不会被垃圾回收机制清除。3. 不可遍历
正因为
WeakMap
对键名所引用的对象是弱引用关系,因此WeakMap
内部成员是会却决于垃圾回收机制有没有执行,运行前后成员个数很可能是不一样的,而垃圾回收机制的执行又是不可预测的,因此不可遍历七、Map 和 WeakMap 的区别
Map
的键可以是任意类型,WeakMap
只接受对象作为键(null除外),不接受其他类型的值作为键Map
的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键;WeakMap
的键是弱引用,键所指向的对象可以被垃圾回收,此时键是无效的Map
可以被遍历,WeakMap
不能被遍历
因为 weakMap 不会影响垃圾回收,所以可以用来关联元数据
文章图片
当上面代码执行后,登录按钮从DOM树中被删除了,但由于 Map 对节点对象是强引用关系,仍然保存着对按钮的引用,所以会引起内存泄漏
文章图片
因此可以采用
WeakMap
当节点删除后,引用计数为0,等待垃圾回收机制回收2. 部署私有属性
利用弱映射,将内部属性设置为实例的弱引用对象,当实例删除时,私有属性也会随之消失,因此不会内存泄漏
阮一峰老师的代码实例
文章图片
3. 数据缓存
当我们需要在不修改原有对象的情况下储存某些属性等,而又不想管理这些数据时,可以使用
WeakMap
文章图片
推荐阅读
- #导入MD文档图片# 漫天的烟火送给遥远的你
- 从零开始写一个微前端框架-沙箱篇
- 讲透学烂二叉树(二叉树的遍历图解算法步骤及JS代码)
- 几种常用设计模式的简单示例
- #导入MD文档图片#WebSocket的前后端使用
- 讲透学烂二叉树(二叉树的笔试题:翻转|宽度|深度)
- Ant Design Pro V4.5 从服务器请求数据的坑(typescript版)#导入MD文档
- Vue实现原理(图文讲解)
- go开发游戏开服程序