Set和WeakSet
Set
ES6 提供了新的数据结构 Set
。它类似于数组,但是成员的值都是唯一的,没有重复的值。需要记录不同成员的又不希望重复记录的情况下可以用到Set
如何生成Set:
let set1 = new Set()
let set2 = new Set([1,2,3])
Set 实例的属性:
-
Set.prototype.size
:返回Set
实例的成员总数。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。
四个操作方法:
-
Set.prototype.add(value)
:添加某个值,返回 Set 结构本身。 -
Set.prototype.delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。 -
Set.prototype.has(value)
:返回一个布尔值,表示该值是否为Set
的成员。 -
Set.prototype.clear()
:清除所有成员,没有返回值。
由于Set中值不会重复,可以用来Set来做数组去重
四个遍历方法:
-
Set.prototype.keys()
:返回键名遍历器 -
Set.prototype.values()
:返回键值遍历器 -
Set.prototype.entries()
:返回键值对遍历器 -
Set.prototype.forEach()
:使用回调函数遍历每个成员
注意:Set实例中key和value是一样的,所以keys()
和values()
这两个方法的结果是一样的
实例
Set中查找某个值是否已经存在的时间复杂度是O(1),而数组的indexOf
方法时间复杂度是O(n),又由于Set中值不会重复,所以可以使用Set做数组去重:
//使用indexOf 缺点:时间复杂度O(n^2)性能低下, NaN要做特殊处理
function deduplicate1(arr) {
let temp =[]
for (let i = 0; i < arr.length; i++) {
if(temp.indexOf(arr[i]) === -1){
temp.push(arr[i])
}
}
return temp
}
//使用对象解决性能问题 但是数组里不能有对象,null,undefined,Boolean值,也无法区分字符串和数字
function deduplicate2(arr) {
let temp = {}
for (let i = 0; i < arr.length; i++) {
if(!temp[arr[i]]){
temp[arr[i]] = true
}
}
return Object.keys(temp)
}
//使用Set来去重
function deduplicate3(arr) {
let temp = [...(new Set(arr))]
return temp
}
WeakSet
WeakSet
结构与 Set
类似,也是不重复的值的集合。但是,它与 Set
有两个区别。
-
WeakSet
的成员只能是对象,而不能是其他类型的值。 -
WeakSet
中的对象都是弱引用
如果一个对象没有任何引用,那么此对象会尽快被垃圾回收,释放掉它占用的内存。
即垃圾回收机制不考虑 WeakSet
对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet
之中。
WeakSet
结构有以下三个方法。
-
WeakSet.prototype.add(value)
:向 WeakSet 实例添加一个新成员。 -
WeakSet.prototype.delete(value)
:清除 WeakSet 实例的指定成员。 -
WeakSet.prototype.has(value)
:返回一个布尔值,表示某个值是否在WeakSet
实例之中。
WeakSet
不能遍历,是因为成员都是弱引用,随时可能消失。
示例:
let div = document.querySelector('div')
let set = new Set()
set.add(div)
//...some code
document.body.removeChild(div)
div = null //dom对象仍在内存中,因为Set中仍然引用此对象
let div = document.querySelector('div')
let weakset = new WeakSet()
weakset.add(div)
//...some code
document.body.removeChild(div)
div = null //dom对象的已经没有引用,将被垃圾回收机制回收