浅析map和weakmap区别以及使用场景(代码片段)

小丞同学 小丞同学     2022-12-28     573

关键词:

在阅读红宝书时遇到了 WeakMap 这个关键字,第一次见感觉没啥用,是我见识浅了,其实还是有点用的,有多大我不知道(快跑)

希望这一篇文章能让你对 Map 有更好的理解,或者能够帮你理解 MapWeakMap

这篇文章会先从Map再到WeakMap

一、为什么是 Map ?

1. 传统对象结构

Map本质上是一个键值对的集合。和传统对象结构相比,传统的对象只能用字符串作为键名,这就在使用上造成了很大的限制了。这也是新增 Map 的原因之一。

const data = ;
// 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方法转化后的结果,以这个值为键名成功的输出了valueobjectData

通过上面的测试,确定了传统对象的键名会通过toString方法转化为字符串类型

注意:在我们访问对象成员时,键名有空格时不能采用点访问,例如data.ab c

这样是错误的。我们需要采用data['ab c']的形式来访问

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 的特点

  1. Map 默认情况下不包含任何键,所有键都是自己添加进去的。不同于 Object 原型链上有一些默认的键。

  2. Map 的键可以是任意类型数据,就连函数都可以。

  3. Map 的键值对个数可以轻易通过size属性获取,Object 需要手动计算。

  4. Map 在频繁增删键值对的场景下性能要比 Object 好。

4. 什么时候用 Map

  1. 要添加的键值名和 Object 上的默认键值名冲突,又不想改名时,用 Map
  2. 需要 String 和 Symbol 以外的数据类型做键值时,用 Map
  3. 键值对很多,有需要计算数量时,用 Map
  4. 需要频繁增删键值对时,用 Map

二、Map 实例属性和方法

在上面我们已经接触到了Map的个别 API,接下来简单说说

1. set

set方法设置键名key对应的键值为value,然后会返回整个Map结构,如果设置的key已经存在,则会更新value值,否则会新生成该键

也可以采用链式写法设置多组数据

成功输出如下:

2. get

通过get方法读取key对应的键值,如果传入的键值不存在,则会返回undefined

控制台成功输出ljc

3. has

判断传入的键是否存在当前Map对象中,该方法返回一个布尔值

在上面的代码中,存在nametrue,不存在sex返回false

4. delete

删除传入的键,返回true,如果删除失败,则返回false

5. clear

清除所有成员,没有返回值

clear前后结果对比,注意clear没有返回值

三、遍历方法

可以采用for...of循环和forEach两种方法。由于Map实例会维护键值对的插入顺序,因此可以根据插入顺序进行遍历

采用for…of

for...of可以遍历有iterator接口的数据结构

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员

map.entries()

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)

那它真正是什么意思呢?

这其实描述的是 JS 中垃圾回收程序对待“弱映射”中键的方式

那为什么要有 WeakMap 呢?它解决了什么问题呢?这些问题后面都会讲到

六、WeakMap 的特性

我们先从 WeakMap 的特性讲起

1. WeakMap 只能将对象作为键名

  • 只接受对象作为键名(null 除外),不接受其他类型的值作为键名

null 除外

正常添加

2. WeakMap 的键名引用的对象是弱引用

这里懵了挺久的,但是这是WeakMap结构的关键所在

要想读懂这句话,不容易,我们需要先知道强引用和弱引用

2.1 什么是强引用?

我们先来看看强引用,这是阮一峰老师书上的例子

在上面的代码中,e1e2是两个对象,通过arr数组对这两个对象添加一些文字说明。但是这样就形成了arre1e2的引用,而这种引用又是强引用。它的区别就体现在。当我们不再需要这两个对象时,我们必须手动的删除这个引用,解除arr都两个对象的引用关系,否则垃圾回收机制不会释放e1e2占用的内存。因为,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);

图一中的数据被mymyMap实例对象所引用,引用计数为 2,图2中建立了myMapmy所引用的对象的弱引用,引用计数为 1

在上面我们谈到强引用数据被删除时,需要手动解除引用,而弱引用则可以等待垃圾回收机制自动清除

弱引用与垃圾回收

当执行my = null时会解除my对原数据的引用,而myMap实例对象对my所引用对象是弱引用关系,该数据的引用计数为 0 ,程序垃圾回收机制在执行时会将引用对象回收。而如果时强引用关系则引用计数为 1 ,不会被垃圾回收机制清除。

总的来说, WeakMap 保持了对键名所引用的对象的弱引用,即垃圾回收机制不将该引用考虑在内。只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。

3. 不可遍历

正因为WeakMap对键名所引用的对象是弱引用关系,因此WeakMap内部成员是会却决于垃圾回收机制有没有执行,运行前后成员个数很可能是不一样的,而垃圾回收机制的执行又是不可预测的,因此不可遍历

了解了WeakMap的特性,相信对“为什么要有WeakMap?”已经有了一定的答案

七、Map 和 WeakMap 的区别

看到这里相信心中已经有答案了

  • Map 的键可以是任意类型,WeakMap 只接受对象作为键(null除外),不接受其他类型的值作为键
  • Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键; WeakMap 的键是弱引用,键所指向的对象可以被垃圾回收,此时键是无效的
  • Map 可以被遍历, WeakMap 不能被遍历

八、WeakMap 的使用场景

1. DOM 节点元数据

用红宝书的例子

因为 weakMap 不会影响垃圾回收,所以可以用来关联元数据

当上面代码执行后,登录按钮从DOM树中被删除了,但由于 Map 对节点对象是强引用关系,仍然保存着对按钮的引用,所以会引起内存泄漏

因此可以采用WeakMap当节点删除后,引用计数为0,等待垃圾回收机制回收

2. 部署私有属性

利用弱映射,将内部属性设置为实例的弱引用对象,当实例删除时,私有属性也会随之消失,因此不会内存泄漏

阮一峰老师的代码实例

3. 数据缓存

当我们需要在不修改原有对象的情况下储存某些属性等,而又不想管理这些数据时,可以使用WeakMap


非常感谢您的阅读,欢迎提出你的意见,有什么问题欢迎指出,谢谢!🎈

weakmap(代码片段)

WeakMap结构与Map结构类似,用于生成键值对的集合。//WeakMap可以使用set方法添加成员constwm1=newWeakMap();constkey=foo:1;wm1.set(key,2);wm1.get(key)//2//WeakMap也可以接受一个数组,//作为构造函数的参数constk1=[1,2,3];constk2=[4,5,6];constwm2=newWeakMap([[k1... 查看详情

es6weakmap和weakset的使用场景

...决这个问题,ES6还引入了另外两种新的数据结构,即称为WeakMap和WeakSet的弱集合。这些集合之所以是“弱的”,是因为它们允许从内存中清除不再需要的被这些集合所引用的对象。 查看详情

es6:数据结构set和map&weakset和weakmap(代码片段)

ES6:数据结构Set和Map&WeakSet和WeakMapSet基本使用常见方法WeakSetWeakSet的特点基本使用WeakMap的应用Map基本使用常见方法WeakMapWeakMap的特点强引用和弱引用在ES6以前存储数据的结构有两种:数组和对象。在ES6中新增两种数据结构:Set... 查看详情

es6:数据结构set和map&weakset和weakmap(代码片段)

ES6:数据结构Set和Map&WeakSet和WeakMapSet基本使用常见方法WeakSetWeakSet的特点基本使用WeakMap的应用Map基本使用常见方法WeakMapWeakMap的特点强引用和弱引用在ES6以前存储数据的结构有两种:数组和对象。在ES6中新增两种数据... 查看详情

深入浅析vue中mixin和extend的区别和使用场景(代码片段)

Vue中有两个较为高级的静态方法mixin和extend,接下来我们来讨论下关于他们各自的原理和使用场景。Mixin:原理:先来看看官网的介绍:参数:Objectmixin用法:混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将... 查看详情

javascriptweakmap(代码片段)

文章目录前言一、为何选用WeakMap1.Map2.WeakMap二、WeakMap原型方法总结前言我在处理一个复杂对象的深拷贝方法时接触到WeakMap,其作为缓存结构以解决对象内部的循环引用问题.为了改造这个方法,决定研究WeakMap.一、为何选用WeakMapWeak... 查看详情

javascriptweakmap(代码片段)

文章目录前言一、为何选用WeakMap1.Map2.WeakMap二、WeakMap原型方法总结前言我在处理一个复杂对象的深拷贝方法时接触到WeakMap,其作为缓存结构以解决对象内部的循环引用问题.为了改造这个方法,决定研究WeakMap.一、为何选用WeakMapWeak... 查看详情

set和map数据结构介绍及使用场景分析

...为map的key---------转自JavaScript复杂判断的更优雅写法--------WeakMap结构与Map结构类似,也是用于生成键值对的集合。区别vue3.0中的数据监听原理简析 查看详情

map和weakmap数据结构

Map和WeakMap是ES6新增的数据结构一、Map它们本质与对象一样,都是键值对的集合,但是他们与Object对象主要的不同是,键可以是各种类型的数值,而Object对象的键只能是字符串类型或者Symbol类型值,Map和WeakMap是更为完善的Hash结构... 查看详情

浅析hashmap和hashtable的区别

HashMap和Hashtable两个类都实现了Map接口,二者保存键值对(key-value对);HashMap和HashTable区别第一,继承的父类不同。HashMap继承自AbstractMap类,而Hashtable继承自Dictionary类,HashMap是Hashtable的轻量级实现(非线程安全的实现),二者... 查看详情

es6通过weakmap解决内存泄漏问题(代码片段)

一、Map1.定义Map对象保存键值对,类似于数据结构字典;与传统上的对象只能用字符串当键不同,Map对象可以使用任意值当键。2.语法newMap([iterable])属性size:返回键值对的数量。操作方法set(key,value):设置(新增/更新)键key的值... 查看详情

《javascript高级程序设计》学习笔记|6.5.weakmap

关注前端小讴,阅读更多原创技术文章WeakMapWeakMap是ECMAScript6的新增特性,是一种新的集合类型,是Map的“兄弟”类型,也是Map的子集“weak”描述的是JS垃圾回收程序对待“弱映射”中键的方式相关代码→基本API使用new关键字和We... 查看详情

TypeScript 找不到名称 Weakmap、Map 等

】TypeScript找不到名称Weakmap、Map等【英文标题】:TypeScriptcannotFindnameWeakmap,Map,etc【发布时间】:2018-12-1013:54:22【问题描述】:我想到了Angular教程,并有这个ts和webpack配置这里是tsconfig"compilerOptions":"target":"es5","module":"es2015","moduleRes... 查看详情

es6中的setmap和weakmap

ES6新增了几种集合类型,本文介绍 Set、Map 和 WeakMap。比较新的Firefox、Chrome(需要在about:flags启用实验性JavaScript)以及IE11都有不同程度的实现。需要注意的是,ES6规范会一直调整,本文只以当前规范及浏览器实现为准... 查看详情

cc2540芯片资料浅析

CC2540是一款高性价比,低功耗片上系统(Soc)解决方案,它适合蓝牙低功耗应用领域,极少的外围元器件以及强大网络节点建立成为可能。CC2540是一款含有高速和低功耗8051内核的RF收发器。适用于低功耗系统,有超低功耗的睡眠... 查看详情

javascript中constvar和let区别浅析

let是修复了var的作用域的一些bug,变的更加好用。let是更好的var。var的作用于是函数作用于,而let是块级别(大括号括起来的内容)const声明的变量只可以在声明时赋值,不可随意修改,这是最大的特点。使用var声明的变量,其... 查看详情

论普通函数和箭头函数的区别以及箭头函数的注意事项不适用场景(代码片段)

...学却对它的了解程度还是不够深...普通函数和箭头函数的区别:箭头函数的this指向规则:1.箭头函数没有prototype(原型),所以箭头函数本身没有thisleta=()=>;console.log(a.prototype);//undefi 查看详情

map和set使用的区别和联系(建议收藏)

我是目录1、搜索:(1)概念及场景(2)模型:2、Map的使用3、Set的使用表现:两个接口:Set和Map接口1、搜索:(1)概念及场景Map和set是一种专门用来进行搜索的容器或者数据结构,... 查看详情