• JS Map与weakMap


    Map

    Map 是 ES6 新增的一种集合类型,他是真正的键/值存储机制,在 ES6 之前通过对象存储“键值对”。

    size 属性

    每一个 Map 实例都有 size 属性,该属性表示该实例有多少对键值对。

    const map1 = new Map([["key", "val"]]);
    console.log(map1.size);// 1
    
    • 1
    • 2

    基本API

    • 构建集 Map 合

    使用 new 关键字创建一个 Map 实例,可以接收一个二维数组,作为初始化的数据。

    const map1 = new Map();
    
    const map2 = new Map([["key", "val"]]);
    console.log(map2.size)//1
    
    const map3 = new Map([[]]);
    console.log(map3.has(undefined))//true
    console.log(map3.get(undefined))//undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 新增键值对

    创建实例后可以通过 set 方法添加键值对。第一个参数是 ,第二个参数是 。可以连续调用。

    const map1 = new Map();
    console.log(map1.size);//0
    
    map1.set("key", "val");
    console.log(map1.size);//1
    
    map1.set("key1", "val1").set("key2", "key2");
    console.log(map1.size);//3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 读取键对应的值

    通过 get 方法获取 Map 实例的键对应的值。如果作为参数的键不在 Map 中则返回 undefined。接收一个参数即键。

    const map1 = new Map();
    map1.set("key", "val");
    console.log(map1.get("key"))//val
    console.log(map1.get("key1"))//undefined
    
    • 1
    • 2
    • 3
    • 4
    • 判断键值对是否存在

    通过 has 方法判断该键是否存在 Map 实例中。存在返回 true,不存在返回 false。

    const map1 = new Map([["key", "val"]]);
    console.log(map1.has("key"))//true
    console.log(map1.has("key1"))//false
    
    • 1
    • 2
    • 3
    • 删除键值对

    通过 delete 方法删除键值对。传入要删除的键。要删除的键在实例中则删除并返回 true,否则返回 false。

    const map1 = new Map([["key", "val"]]);
    console.log(map1.delete("key"))//true
    console.log(map1.size);
    console.log(map1.delete("key1"))//false
    
    • 1
    • 2
    • 3
    • 4
    • 清空 Map 集合

    通过 clear 方法清空 Map 实例的键值对。

    const map1 = new Map([["key", "val"]]);
    console.log(map1.size);//1
    map1.clear();
    console.log(map1.size);//0
    
    • 1
    • 2
    • 3
    • 4
    • 对象作为键

    Map 可以使用任意 JS 类型作为键,但是 Object 只能以数值、字符串、符号作为键。这意味着 Map 可以使用对象作为键。并且 Map 使用 SameValueZero(类似于严格对象相等)来确定键的匹配性。所以当对象作为键时,更改对象的属性并不会丢失映射关系

    const obj = {}
    const map1 = new Map([[obj, "val"]]);
    console.log(map1.get(obj));//val
    obj.name = "123";
    console.log(map1.get(obj));//val
    
    • 1
    • 2
    • 3
    • 4
    • 5

    迭代

    Map 能够按照键值对的插入顺序迭代输出。并且 Map 实例提供了一个迭代器以便能够通过特特定方法按顺序迭代。

    • entries

    调用本方法会返回一个迭代器,并且是默认迭代器。所以可以使用扩展操作符,使用 for of 迭代 Map 实例时可以省略显示调用 entries();

    const map1 = new Map([[1, 1], [2, 2]]);
    for (let item of map1.entries()) {
      console.log(item);
    }
    console.log("-----------");
    for (let item of map1) {
      console.log(item);
    }
    console.log("-----------");
    console.log([...map1]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    • keys

    调用本方法会返回一个按照插入顺序的键的迭代器。

    const map1 = new Map([[1, 1], [2, 2]]);
    for (let item of map1.keys()) {
      console.log(item);
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    • values

    调用本方法会返回一个按照插入顺序的值的迭代器。

    const map1 = new Map([[1, 1], [2, 2]]);
    for (let item of map1.values()) {
      console.log(item);
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    • 不使用迭代器
      当然也可以不使用迭代器而是用回调的方式迭代,示例如下。回调函数的第一个参数是值,第二个参数是键。
    const map1 = new Map([[1, 1], [2, 2]]);
    map1.forEach((val, key) => {
      console.log(key + ":" + val);
    })
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    需要注意的是如果在迭代过程中修改给了每次迭代的结果,并不会影响映射关系,如下例

    const map1 = new Map([[1, 1], [2, 2]]);
    for (let item of map1.keys()) {
      item = 3;
      console.log(item);
    }
    console.log(map1.get(1));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    由输出结果可知在遍历的过程中使 item 的值为 3,因此输出两次 3,最后通过原键仍然拿到了值。

    Map 与 Object 最佳实践

    大部分情况下使用 Object 和 Map 区别并不大,下面只是给出一些小小的建议。

    • 插入和删除性能:对于大多数浏览器引擎来说,当涉及到大量的插入和删除操作时,Map 的性能要优于 Object。
    • 查找速度:数据量非常大时,两者速度相差极小,如果涉及大量的查找操作,在一定条件下 Object 速度更快。
    • 内存:对于大多数浏览器来说,相同的内存,Map 大约可以比 Object 多存 50% 的键值对。

    weakMap

    weakMap 也是 ES6 新增的一种集合类型,它有如下特点:

    1. 键只能是 Object 类型或继承自 Object 类型,否则会抛出错误
    2. weakMap 实例对该键 Object 是弱引用(后边会详细讲),不会影响 JS 的垃圾回收
    3. weakMap 的基本 API 比 Map 的少了 clear(清空)方法,因为特点2,所以没有必要再持有该方法。
    4. weakMap 没有提供迭代其实例键值对的迭代器。因为特点2,所以 weakMap 实例中的键值对随时随地都有可能被销毁。
    5. weakMap 实例没有 size 属性
    6. weakMap 也可以像构建 Map 那样构建,也有 set、get、has、delete方法。

    什么是弱引用

    JS 有一种垃圾回收策略叫做引用计数,通俗理解就是声明一个对象后,JS 就会使用一个变量用来保存该对象被使用的次数,如果被使用次数为 0 ,那么 JS 就会销毁该对象,释放内存。

    给个例子

    const obj1 = { name: 1 }, obj2 = { name: 2 };
    const map = new WeakMap([[obj1, 1], [obj2, 2]]);
    
    • 1
    • 2

    这里弱引用的意思是当我实例化了一个 weakMap 集合 map,并且使用 obj1 和 obj2 作为键值对的键存入 map 中,那么此时 map 使用 obj1 和 obj2,但是由于 map 是 weakMap 实例,所以 obj1 和 obj2的被使用次数并不会加 1,那么一旦 obj1 和 obj2 又没有在别的地方被使用,JS 就会回收 obj1 和 obj2,map 就失去了键,自然获取不到值。

    因此 weakMap 实例没有提供迭代器,因为也许你刚迭代完,该键就被回收了,内存都被释放了,那么此时的迭代就没有了意义。也正因此 weakMap 舍弃了 clear API。并且即使能够访问 weakMap 实例也无法看到其存储的键值对。

    但是需要注意的是 weakMap 的值并不是弱引用,只要键存在,那么它对应的值一定不会被 JS 回收。

    还需要注意 weakMap 的好兄弟 Map 就不是这样,Map 实例对于键的应用是强引用,只要 Map 实例没被回收,那么其存储键值对就会一直存在,不会被 JS 私自回收。

    我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

  • 相关阅读:
    2022速卖通宠物用品热销及需求品类推荐!
    下册开学期末+CSP-J游记
    leetcode309最佳买卖股票时机含冷冻期刷题打卡
    BiLSTM(双向LSTM)实现股票预测(TensorFlow2版)|时间序列预测
    IntelliJ IDEA 记学习笔 Maven自动导包 Auto Import
    传奇GOM引擎单机架设图文教程
    介绍油封的存放方法?
    leetcode6. Z 字形变换python_字符串
    AD7793驱动程序(详细)
    【论文笔记】MiniSeg: An Extremely Minimum Network for Efficient COVID-19 Segmentation
  • 原文地址:https://blog.csdn.net/weixin_46015333/article/details/127758441