Set、Map和WeakSet、WeakMap

map和set的区别

  • set类似于数组的集合,无序,插入删除速度快,里面的元素不重复,查找速度快

  • Map是一个类似于对象的数组结构,和对象不同的在于他的key可以是任意类型,对象只能用string和symbol类型,一般用作存储数据

  • 1.Map是键值对,Set是值的集合,当然键和值可以是任何的值;

    2.Map可以通过get方法获取值,而set不能因为它只有值;

    3.都能通过迭代器进行for...of遍历;

    4.Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储

    5.map和set都是stl中的关联容器,map以键值对的形式存储,key=value组成pair,是一组映射关系。set只有值,可以认为只有一个数据,并且set中元素不可以重复且自动排序。

    Set

    Set对象允许你存储任何类型的值,无论是原始值或者是对象引用。它类似于数组,但是成员的值都是唯一的,没有重复的值。

    Set 本身是一个构造函数,用来生成Set 数据结构。Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

    Set中的特殊值

    Set 对象存储的值总是唯一的,所以需要判断两个值是否恒等。有几个特殊值需要特殊对待:

    +0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复

    undefined 与 undefined 是恒等的,所以不重复

    NaN 与 NaN 是不恒等的,但是在 Set 中认为NaN与NaN相等,所有只能存在一个,不重复。

    Set实例对象的属性

    size:返回Set实例的成员总数

    Set实例对象的方法

    add(value):添加某个值,返回 Set 结构本身(可以链式调用)。

    delete(value):删除某个值,删除成功返回true,否则返回false。

    has(value):返回一个布尔值,表示该值是否为Set的成员。

    clear():清除所有成员,没有返回值。

    数组去重(利用扩展运算符)

    Map

    Map对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。构造函数Map可以接受一个数组作为参数。

    Map和Object的区别

    一个Object 的键只能是字符串或者 Symbols,但一个Map 的键可以是任意值。

    Map中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。

    Map的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。

    Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。

    Map对象的属性

    size:返回Map对象中所包含的键值对个数

    Map对象的方法

    set(key, val): 向Map中添加新元素

    get(key): 通过键值查找特定的数值并返回

    has(key): 判断Map对象中是否有Key所对应的值,有返回true,否则返回false

    delete(key): 通过键值从Map中移除对应的数据

    clear(): 将这个Map中的所有元素删除

weakmap和weakset

WeakSet

为啥需要WeakSet

    let set =new Set(),key={};
    set.add(key)
    console.log(set.size) //1
    //移除原始引用
    key=null
    console.log(set.size) //1
    key=[...set][0] //取回原始引用

上例中就是当我们设置key的值为null,清除了原始引用,但Set实例中任存在着一个对该对象的强引用,导致最终我们还能访问到该对象,这样的话会导致内存无法释放,进而可能会引发内存泄漏。所以,为了解决这个问题,WeakSet类型就出现了,看名字就可以知道,弱引用Set集合,WeakSet 只存储对象的弱引用,垃圾回收机制不考虑 WeakSet 对该对象的引用,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存。

特性

  • WeakSet结构同样不会存储重复的值,它的成员只能是对象类型。

  • 因为垃圾回收机制可能随时清除其中的对象,所以不可以进行forEach()遍历、for-of循环等迭代操作

  • 因为弱引用, WeakSet 结构没有keys()alues()entries()等方法和size属性

声明定义

WeakSet 是一个构造函数,可以接受一个数组或类似数组的对象作为参数 ,可以使用new命令,创建 WeakSet 数据结构。

  const a = [[1, 2], [3, 4]];
  const ws = new WeakSet(a); // WeakSet {[1, 2], [3, 4]}
  复制代码

基本操作

由于弱引用带来的限制,WeakSet只支持三种基本操作。

  • add(value):向 WeakSet 实例添加一个新成员。

  • delete(value):清除 WeakSet 实例的指定成员。

  • has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。

  const ws = new WeakSet();
  const obj = {};
  const foo = {};
  ​
  ws.add(window);
  ws.add(obj);
  ​
  ws.has(window); // true
  ws.has(foo);    // false
  ​
  ws.delete(window);
  ws.has(window);    // false
  复制代码

具体使用场景

根据上文我们可以得知,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。具体一个场景就是存储DOM对象,当我们存储的DOM对象元素被另外一段脚本移除,我们也不想保留这些元素的引用而造成内存泄漏,就可以使用WeakSet来存储。

👉存储DOM元素

  const ws = new WeakSet();
  document.querySelectorAll("button").forEach(item => Ws.add(item));
  复制代码

WeakMap

为啥需要WeakMap

相对的,WeakMap也是弱引用的Map集合,所以同理,希望避免Map集合中保存对象的强引用而导致的内存泄漏问题,使用WeakMap数据结构来保存对象的弱引用,与WeakSet不同的是WeakMap中存储的是键值对,WeaMap对键名是弱引用的,键值是正常引用,如果键在其他地方不被引用时,垃圾回收机制就会自动回收这个对象所占用的内存空间,同时移除WeakMap中的键值对,但键名对应的值如果是一个对象,则保存的是对象的强引用,不会触发垃圾回收机制被回收。

特性

  • WeakMap中存储的是许多键值对的无序列表,列表的键名必须是非null的对象,对应的值可以是任意类型

  • WeaMap对键名是弱引用的,键值是正常引用

  • 因为垃圾回收机制可能随时清除其中的对象,所以不可以进行forEach( )遍历等操作

  • 因为弱引用,WeaMap 结构没有keys( ),values( ),entries( )等方法和 size 属性

声明定义

  1. WeakMap 可以使用 set 方法添加成员

  2. WeakMap 也可以接受一个数组,作为构造函数的参数

  // WeakMap 可以使用 set 方法添加成员
  const wm1 = new WeakMap();
  const key = {foo: 1};
  wm1.set(key, 2);
  wm1.get(key) // 2
  ​
  // WeakMap 也可以接受一个数组,
  // 作为构造函数的参数
  const k1 = [1, 2, 3];
  const k2 = [4, 5, 6];
  const wm2 = new WeakMap([[k1, 'foo'], [k2, 'bar']]);
  wm2.get(k2) // "bar"
  复制代码

基本操作

因为垃圾回收机制的运行无法预测,所以 没有办法列出所有键名,某个键名是否存在完全不可预测,,为了防止出现不确定性,就统一规定不能取到键名,二是无法清空,即不支持clear方法。因此,WeakMap只有四个方法可用:get()set()has()delete()

  • set(key,value):向 WeakMap 实例添加一个新成员,返回当前的WeakMap对象。

  • delete(key):清除 WeakMap 实例的指定成员,返回true。如果删除失败,返回false。

  • has(key):返回一个布尔值,表示某个值是否在 WeakMap 实例之中。

  • get(key):读取key对应的键值,如果找不到key,返回undefined。

  const wm = new WeakMap();
  let key = {};
  let obj = {foo: 1};
  ​
  wm.set(key, obj);
  ​
  wm.get(key); //{foo: 1}
  ​
  wm.has(key); //true
  ​
  wm.delete(key);//true
  复制代码

具体使用场景

WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失,如果不想保存对象的引用干扰垃圾回收机制,就可以使用 WeakMap。

👉存储DOM元素

将一个 DOM 节点作为键名存入该实例,并将一些附加信息作为键值,一起存放在 WeakMap 里面。这时,WeakMap 里面对element的引用就是弱引用,一旦将这个 DOM 节点删除,该element对象就会自动被垃圾回收机制清除,不存在内存泄漏风险。

  <body>
    <div>bar</div>
    <div>foo</div>
  </body>
  <script>
    const wm = new WeakMap();
    document
      .querySelectorAll("div")
      .forEach(item => wm.set(item, item.innerHTML));
    console.log(wm); //WeakMap {div => "bar", div => "foo"}
  </script>
  复制代码

👉存储私有变量

ES5中我们经常利用立即执行函数的方式来设置私有变量,但问题是私有变量不会随着实例对象的销毁被回收,WeakMap正好可以解决这个问题。

  let Person=(function(){
      let privateData = new WeakMap();
      function Person(name){
          privateData.set(this,{name})
      }
      Person.prototype.getName = function(){
          return privateData.get(this).name
      }
      return Person
      
  }())
当调用Person构造函数时,实例就会被添加到WeakMap集合中,键是this, 是实例的弱引用,值是私有属性name的对象, 如果删除实例,私有属性也就随之消失,不会造成内存泄漏。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值