详解 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 = newMap();
// 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 的键值对个数可以「轻易」通过size属性获取,Object 需要手动计算。
  • Map 在频繁增删键值对的场景下「性能」要比 Object 好。

4. 什么时候用 Map

要添加的键值名和 Object 上的默认键值名冲突,又不想改名时,「用 Map」
需要 String Symbol 以外的数据类型做键值时,「用 Map」
键值对很多,有需要计算数量时,「用 Map」
需要频繁增删键值对时,「用 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

三、遍历方法

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

采用「for...of」

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

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

map.entries()

在Map实例中「有一个迭代器」,能以插入顺序生成[key,value]形式的数据。

也可以采用如下进行遍历,每次item获取到一个数组

通过回调的方式遍历map

四、Map 类型转化

几种与map相互类型转化的方法

Map 转为数组

通过扩展运算符实现

let map = newMap()
let arr = [...map]

数组转为 Map

let map = newMap(arr)

Map 转为对象

通过遍历利用set将键值对加入对象中

let obj = {}
for (let [k, v] of map) {
  obj[k] = v
}
对象转为 Map
for( let k ofObject.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 什么是强引用?

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

「麻烦的操作势必会造成问题,当忘记了手动删除引用,就会造成内存泄漏」

2.2 什么是弱引用?

对于「弱引用」,百度百科给出的答案:

在计算机程序设计中,弱引用与强引用相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。

也就是说「如果」我们能这样创建一个弱引用的对象

//假设
let obj = new WeakObject()

我们就可以静静的等待垃圾车来把它拖走了,obj所引用的对象就会被回收

如果还没有理解的话,我们再来看看

2.3 弱引用和强引用图解

从1套代码结合两张图来理解

对于强引用:

const myMap = newMap()
let my = {
    name: "ljc",
    sex: "男"
}
myMap.set(my, 'info');
console.log(myMap);

对于弱引用

const myMap = newWeakMap()
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」 ,不会被垃圾回收机制清除。

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

3. 不可遍历

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

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

七、Map 和 WeakMap 的区别

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

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

八、WeakMap 的使用场景

1. DOM 节点元数据

用红宝书的例子

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

2. 部署私有属性

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

阮一峰老师的代码实例

3. 数据缓存

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

到此这篇关于详解 Map 和 WeakMap 区别以及使用场景的文章就介绍到这了,更多相关Map 和 WeakMap 区别以及使用场景内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!到此这篇关于详解 Map 和 WeakMap 区别以及使用场景的文章就介绍到这了,更多相关Map 和 WeakMap 区别以及使用场景内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JavaScript WeakMap使用详解

    WeakMap 对象是一组键/值对的集合,其中的键是弱引用的.其键必须是对象,而值可以是任意的. 语法 new WeakMap([iterable]) 参数 iterable Iterable 是一个数组(二元数组)或者其他可迭代的且其元素是键值对的对象.每个键值对会被加到新的 WeakMap 里.null 会被当做 undefined. 描述 WeakMap 的 key 只能是 Object 类型. 原始数据类型 是不能作为 key 的(比如 Symbol). Why WeakMap? 在 J

  • 详解 Map 和 WeakMap 区别以及使用场景

    一.为什么是 Map ? 1. 传统对象结构 Map本质上是一个键值对的集合.和传统对象结构相比,传统的对象只能用「字符串作为键名」,这就在使用上造成了很大的限制了.这也是新增 Map 的原因之一. const data = {}; // element 为节点对象 const element = document.querySelector(".node"); console.log(element); // 输出 div.node 对象 // 将对象转化成字符串输出 [object

  • ES6 系列之 WeakMap的使用示例

    前言 我们先从 WeakMap 的特性说起,然后聊聊 WeakMap 的一些应用场景. 特性 1. WeakMap 只接受对象作为键名 const map = new WeakMap(); map.set(1, 2); // TypeError: Invalid value used as weak map key map.set(null, 2); // TypeError: Invalid value used as weak map key 2. WeakMap 的键名所引用的对象是弱引用

  • JavaScript中Object、map、weakmap的区别分析

    前言 ECMAScript 6以前,在JavaScript中实现"键/值"式存储可以使用Object来方便高效地完成,也就是使用对象属性作为键,再使用属性来引用值.但这种实现并非没有问题,为此TC39委员会专门为"键/值"存储定义了一个规范.作为ECMAScript 6的新增特性,Map是一种新的集合类型,为这门语言带来了真正的键/值存储机制.Map的大多数特性都可以通过Object类型实现,但二者之间还是存在一些细微的差异.具体实践中使用哪一个,还是值得细细甄别.

  • Java基本数据类型与封装类型详解(int和Integer区别)

    int是java提供的8种原始数据类型之一. Java为每个原始类型提供了封装类,Integer是java为int提供的封装类(即Integer是一个java对象,而int只是一个基本数据类型).int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer.在JSP开发中,Integer的默认为null,所以用el表达式在文本框中显示时,值为空白字

  • Java 详解Map集合之HashMap和TreeMap

    目录 HashMap 创建HashMap 添加元素 访问元素 删除元素 TreeMap 创建TreeMap 添加元素 访问元素 删除元素 HashMap.TreeMap区别 Map接口储存一组成对的键-值对象,提供key(键)到value(值)的映射,Map中的key不要求有序,不允许重复.value同样不要求有序,但可以重复.最常见的Map实现类是HashMap,他的储存方式是哈希表,优点是查询指定元素效率高. Map接口被HashMap和TreeMap两个类实现. HashMap HashM

  • 详解redis中的锁以及使用场景

    分布式锁 什么是分布式锁? 分布式锁是控制分布式系统之间同步访问共享资源的一种方式. 为什么要使用分布式锁? ​ 为了保证共享资源的数据一致性. 什么场景下使用分布式锁? ​ 数据重要且要保证一致性 如何实现分布式锁? 主要介绍使用redis来实现分布式锁 redis事务 redis事务介绍: ​ 1.redis事务可以一次执行多个命令,本质是一组命令的集合. ​ 2.一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入 ​ **作用:**一个队列中,一次性.顺序性.排他性的执

  • 详解Java 反射和反射的应用场景

    反射机制介绍 JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制. 获取 Class 对象的两种方式 如果我们动态获取到这些信息,我们需要依靠 Class 对象.Class 类对象将一个类的方法.变量等信息告诉运行的程序.Java 提供了两种方式获取 Class 对象: 1.知道具体类的情况下可以使用: Class alunbarCla

  • 详解golang执行Linux shell命令完整场景下的使用方法

    目录 1. 执行命令并获得输出结果 2. 将stdout和stderr分别处理 3. 异步执行命令 4. 执行时带上环境变量 5. 预先检查命令是否存在 6. 两个命令依次执行,管道通信 7. 按行读取输出内容 8. 获得exit code 1. 执行命令并获得输出结果 CombinedOutput() 执行程序返回 standard output and standard error func main() { cmd := exec.Command("ls", "-lah

  • java如何对map进行排序详解(map集合的使用)

    今天做统计时需要对X轴的地区按照地区代码(areaCode)进行排序,由于在构建XMLData使用的map来进行数据统计的,所以在统计过程中就需要对map进行排序. 一.简单介绍Map 在讲解Map排序之前,我们先来稍微了解下map.map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等.其中这四者的区别如下(简单介绍): HashMap:我们最常用的Map,它根据key的HashCode 值来存储数据,根据key可以直接

  • 详解ES6通过WeakMap解决内存泄漏问题

    一.Map 1.定义 Map对象保存键值对,类似于数据结构字典:与传统上的对象只能用字符串当键不同,Map对象可以使用任意值当键. 2.语法 new Map([iterable]) 属性 size:返回键值对的数量. 操作方法 set(key, value):设置(新增/更新)键key的值为value,返回Map对象. get(key):读取键key的值,没有则返回undefined. has(key):判断一个Map对象中是否存在某个键值对,返回true/false. delete(key):

  • 详解mybatis #{}和${}的区别、传参、基本语法

    1 #{}和${}的区别.及注入问题 (1) 区别: 首先清楚一点,动态 SQL 是 mybatis 的强大特性之一,在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析,#{} 和 ${} 在预编译中的处理是不一样的: 例如:select * from t_user where userName = #{name}; #{}预编译:用一个占位符 ? 代替参数:select * from t_user where userName = ? #{}预编

  • 详解JSONObject和JSONArray区别及基本用法

     一.JSONObject和JSONArray的数据表示形式 JSONObject的数据是用 {  } 来表示的, 例如:   { "id" : "123", "courseID" : "huangt-test", "title" : "提交作业", "content" : null  }  而JSONArray,顾名思义是由JSONObject构成的数组,用  [

随机推荐