一、Set
1.定义
ES6中提供了Set数据容器,一个能够存储无重复值的有序列表。Set本身是一个构造函数,用来生成 Set 数据结构。Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。
Set内部使用Object.is()方法来判断两个数据项是否相等,唯一不同的是+0和-0在Set中被判断为是相等的。
示例:
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
//接受数组为参数
const set = new Set([1, 2, 3, 4, 4]);
//接受类似数组为参数
const set = new Set(document.querySelectorAll('div'));
2.用法和注意事项
(1)数组去重
以前需要写多行代码,现在一行就实现 [...new Set(array)]
//Array.from方法可以将 Set 结构转为数组。
const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);
//这就提供了去除数组重复成员的另一种方法。
function dedupe(array) {
return Array.from(new Set(array));
}
dedupe([1, 1, 2, 3]) // [1, 2, 3]
(2)字符串去重
[...new Set('ababbc')].join('')
(3)set不发生数据转换
向 Set 加入值的时候,不会发生类型转换,所以5和"5"是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为NaN不等于自身。
另外,两个对象总是不相等的。及时他们是空对象
3.set实例的属性和方法
(1)属性
Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。
(2)常用方法
Set.prototype.add(value):添加某个值,返回 Set 结构本身。
Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
Set.prototype.clear():清除所有成员,没有返回值。
(3)遍历方法
Set.prototype.keys():返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries():返回键值对的遍历器
Set.prototype.forEach():使用回调函数遍历每个成员
keys方法、values方法、entries方法返回的都是遍历器对象。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。entries方法返回的遍历器,同时包括键名和键值,所以每次输出一个数组,它的两个成员完全相等。
(4)forEach方法
forEach方法的参数就是一个处理函数。该函数的参数与数组的forEach一致,依次为键值、键名、集合本身(上例省略了该参数)。这里需要注意,Set 结构的键名就是键值(两者是同一个值),因此第一个参数与第二个参数的值永远都是一样的。
另外,forEach方法还可以有第二个参数,表示绑定处理函数内部的this对象。
4.weakSet
(1)WeakSet 是一个构造函数,可以使用new命令,创建 WeakSet 数据结构。作为构造函数,WeakSet 可以接受一个数组或类似数组的对象作为参数。
(2)WeakSet 没有size属性,没有办法遍历它的成员。WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了
(3)WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏。
二、Map
1.定义
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,键的去重是通过Object.is()方法进行比较,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
2.用法和注意事项
(1)任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数,Set和Map都可以用来生成新的 Map。
(2)如果对同一个键多次赋值,后面的值将覆盖前面的值。
(3)如果读取一个未知的键,则返回undefined。
(4)只有对同一个对象的引用,Map 结构才将其视为同一个键
(5)Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键
(6)如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键,比如0和-0就是一个键,布尔值true和字符串true则是两个不同的键。另外,undefined和null也是两个不同的键。虽然NaN不严格相等于自身,但 Map 将其视为同一个键。
3.实例属性和方法
(1)size 属性
size属性返回 Map 结构的成员总数。
(2)Map.prototype.set(key, value)
set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
(3)Map.prototype.get(key)
get方法读取key对应的键值,如果找不到key,返回undefined。
(4)Map.prototype.has(key)
has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
(5)Map.prototype.delete(key)
delete方法删除某个键,返回true。如果删除失败,返回false。
(6)Map.prototype.clear()
clear方法清除所有成员,没有返回值。
(7)遍历方法同Set
4.weakMap
(1)weakMap结构与Map结构类似,也是用于生成键值对的集合。weakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
(2)weakMap的键名所指向的对象,不计入垃圾回收机制。
(3)weakMap的专用场合就是,它的键所对应的对象,可能会在将来消失。weakMap结构有助于防止内存泄漏。
(4)weakMap弱引用的只是键名,而不是键值。键值依然是正常引用。
(5)没有遍历操作(即没有keys()、values()和entries()方法),也没有size属性
三、总结
-
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 中被移除。