一、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 中被移除。