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 属性
声明定义
-
WeakMap 可以使用 set 方法添加成员
-
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的对象, 如果删除实例,私有属性也就随之消失,不会造成内存泄漏。