ES6 中的新数据结构 Set & Map 详解

ES6 之 Set、Map:

  • Set 数据结构
  • Map 数据结构
  • WeakSet 和 WeakMap

1. 理解 Set 和 Map

  • Set 相当于是一种叫集合的数据结构,集合的元素都是唯一的,即 Set 数据中的元素是不重复出现的。
  • Map 相当于是一种叫字典的数据结构,字典里的元素也是不重复的,即 Map 中的元素是不重复出现的。Map 和 Set 的不同在于 Map 是键值对形式出现的。
  • 共同点:集合、字典都可以存储不重复的值
  • 不同点:集合是以[值,值]的形式存储元素,字典是以[键,值]的形式存储

2.ES6中的Set

1. Set 是一个构造函数,可以用来 new 一个实例。

let set = new Set()
set = [1,2,"red"]

2. Set 的常规方法:

  • add() 增,返回增后 Set 结构本身
  • delete() 删,返回布尔值,表示删除是否成功
  • has() 查,返回布尔值,判断该元素是否为 Set 成员
  • clear() 清除,无返回值,清除所有成员
  • size() 返回数据长度
let set = new Set()
set.add(1).add(2).add(3).add(3)

console.log(set) //Set(3) { 1, 2, 3 }
console.log(set.size) //3

set.delete(3)
console.log(set) //Set(2) { 1, 2 }

console.log(set.has(1)) //true

set.clear()
console.log(set) //Set(0) {}

3. Set 的遍历方法:

  • keys() : 返回键名
  • values() : 返回键值
  • entries() : 返回键值对
  • forEach() : 遍历每个成员,可传入回调函数,该回调函数有三个参数
let set = new Set(['red', 'green', 'blue'])
for (let item of set.keys()) {
  console.log(item)
} //

console.log('---------------------')

for (let item of set.values()) {
  console.log(item)
} //

console.log('---------------------')

for (let item of set.entries()) {
  console.log(item)
} //

console.log('---------------------')

set.forEach(function (value, key, ownerSet) {
  console.log(value)
  console.log(key)
})

4. 将 Set 转换成数组(利用 Set 实现数组去重)

let set = new Set([1,2,3,3])
console.log(set) // {1,2,3}
let [...arr] = set
comsole.log(arr) // [1,2,3]

5. WeakSet

Set在存放对象时,实际上是存放的是对象的引用,即Set也被称之为Strong Set。如果所存储的对象被置为null,但是Set实例仍然存在的话,对象依然无法被垃圾回收器回收,从而无法释放内存。

let set = new Set();
let key={};
let key2 = {};
set.add(key);
set.add(key2);
console.log(set.size); //2

key=null;
console.log(set.size); //2,无法回收
如果想让对象key正常释放的话,可以使用Weak Set,此时,存放的是对象的弱引用,当对象只被Set弱引用的话,并不会阻止对象实例被回收。Weka Set同Set的用法几乎一致。可以使用add()方法增加数据项,使用has()方法检查Weak Set中是否包含某项,以及使用delete()方法删除某一项。

 差异:

  • 对于Weak Set实例,若调用了add()方法时传入了非对象的参数,则会抛出错误。如果在has()或者delete()方法中传入了非对象的参数则会返回false;
  • Weak Set不可迭代,因此不能用于for-of循环;
  • Weak Set 无法暴露出任何迭代器(例如 keys() 与 values() 方法) ,因此没有任何编程手段可用于判断 Weak Set 的内容;
  • Weak Set没有forEach()方法;
  • Weak Set没有size属性;

3. ES6中的Map

ES6中提供了Map数据结构,能够存放键值对,其中,键的去重是通过Object.is()方法进行比较,键的数据类型可以是基本类型数据也可以是对象,而值也可以是任意类型数据。

Map 的方法:

  • set() : 添加键值对
  • get() : 获取值
  • has() : 查
  • delete :删
  • clear() : 清

1.  使用set()方法可以给 Map 添加键值对

 let map = new Map();
 map.set('title','hello world');// 一个键值对
 map.set('year','2022');// 一个键值对
 
 console.log(map.size); //通过set()方法往Map中增加了两个键值对后,可以看到Map的大小就为2;

 2. 通过get()方法可以从 Map 中提取值

 let map = new Map();
 map.set('title','hello world');
 map.set('year','2022');
 
 console.log(map.get('title')); // hello world

 3.  has(),delete()以及clear()方法

let map = new Map();
map.set('title','hello world');
map.set('year','2022');

console.log(map.has('year')); //true
map.delete('title');
console.log(map.has('title')); //false
map.clear();
console.log(map.size); //0

 4. Map 的初始化

//使用数组来创建Map
let map = new Map([['title','hello world'],['year','2022']]);
console.log(map.has('title')); //true
console.log(map.has('year')); //true
console.log(map.size); //2

5. Map 的 forEach 方法 

与 Set 一样,Map也拥有forEach方法,该方法也接收一个回调函数,该回调函数有三个参数:

  1. 键值对的键;

  2. 键值对的值;

  3. 当前Map对象引用;

 let map = new Map([['title','hello world'],['year','2022']]);
 map.forEach((value,key,ownerMap)=>{
     console.log(value);
     console.log(key);
 });
 
 hello world
 title
 2022
 year

6. WeakMap

Weak Map对Map而言,就像是Weak Set相对于Set一样:Weak Map(或者Weak Set)都是存储对象弱引用的方式,在Weak Map(或者Weak Set)中,所有的键都必须是对象(尝试使用非对象的键会抛出错误),而且这些对象都是弱引用,不会干扰到垃圾回收。当Weak Map中的键在Weak Map之外不存在引用时,该键值对会被移除。
  1. Weak Map的初始化

Weak Map的键必须是对象,值可以是任意类型,初始化同Map一样,也可是使用数组来创建一个 Weak Map :

//使用数组来创建一个Weak Map
let key = {};
let key2 = {};
let map = new WeakMap([[key,'hello'],[key2,'world']]);
console.log(map.get(key)); //hello
console.log(map.get(key2)); //world
  1. has方法以及delete方法

与Map一样,可以使用has()方法来检查Weak Map中是否存在某一个键值对,使用delete()方法可以删除一个键值对。clear() 方法不存在,这是因为没必要对键进行枚举,并且枚举 Weak Map 也是不可能的,这与 Weak Set 相同:

let key = {};
let key2 = {};
let map = new WeakMap([[key,'hello'],[key2,'world']]);

map.delete(key);
console.log(map.has(key)); //false

Weak Map 的用法与局限性

当决定是要使用 Weak Map 还是使用正规 Map 时,首要考虑因素在于你是否只想使用对象类型的键。如果你打算这么做,那么最好的选择就是 Weak Map 。因为它能确保额外数据在不再可用后被销毁,从而能优化内存使用并规避内存泄漏。

要记住 Weak Map 只为它们的内容提供了很小的可见度,因此你不能使用 forEach() 方法、size 属性或 clear() 方法来管理其中的项。如果你确实需要一些检测功能,那么正规 Map会是更好的选择,只是一定要确保留意内存的使用。

4.总结

  • Set 是无重复值的有序列表。根据 Object.is()方法来判断其中的值不相等,以保证无重复。 Set 会自动移除重复的值,因此你可以使用它来过滤数组中的重复值并返回结果。 Set并不是数组的子类型,所以你无法随机访问其中的值。但你可以使用has() 方法来判断某个值是否存在于 Set 中,或通过 size 属性来查看其中有多少个值。 Set 类型还拥有forEach()方法,用于处理每个值。

  • Weak Set 是只能包含对象的特殊 Set 。其中的对象使用弱引用来存储,意味着当 Weak Set中的项是某个对象的仅存引用时,它不会屏蔽垃圾回收。由于内存管理的复杂性, Weak Set的内容不能被检查,因此最好将 Weak Set 仅用于追踪需要被归组在一起的对象。

  • Map 是有序的键值对,其中的键允许是任何类型。与 Set 相似,通过调用 Object.is()方法来判断重复的键,这意味着能将数值 5 与字符串 "5" 作为两个相对独立的键。使用set() 方法能将任何类型的值关联到某个键上,并且该值此后能用 get() 方法提取出来。Map 也拥有一个 size 属性与一个 forEach() 方法,让项目访问更容易。

  • Weak Map 是只能包含对象类型的键的特殊 Map 。与 Weak Set 相似,键的对象引用是弱引用,因此当它是某个对象的仅存引用时,也不会屏蔽垃圾回收。当键被回收之后,所关联的值也同时从 Weak Map 中被移除。


参考文献:
作者:你听___
链接:https://www.jianshu.com/p/af78964c33e2
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 
posted @ 2022-05-08 14:21  RHCHIK  阅读(442)  评论(0编辑  收藏  举报