Set/weakSet

Set

用于存储任何类型的唯一值,无论是基本类型还是对象引用。

  • 只能保存值没有键名
  • 严格类型检测如字符串数字不等于数值型数字
  • 值是唯一的
  • 遍历顺序是添加的顺序,方便保存回调函数

基本使用

对象属性最终都会转为字符串

const obj = {1: 'mkimq', '1': 'mkimq.com'}
console.log(obj) // {1: 'mkimq.com'}

const mk = {[obj]: 'web'}
console.log(mk[obj.toString()])
console.log(mk['[object Object]'])

使用数组作为初始值

const set = new Set(['mkimq', 'mkimq.com'])

Set 中是严格类型约束的,下面的数值1与字符串1属于两个不同的值

const set = new Set()
set.add(1)
set.add('1')

console.log(set)

使用 add 添加元素,不允许重复添加

获取数量

获取元素数量

const set = new Set(['mkimq', 'mkimq.com'])
set.size

元素检测

检测元素是否存在

const set = new Set(['mkimq', 'mkimq.com'])
set.has('mkimq')

删除元素

使用 delete 方法删除单个元素,返回值为boolean类型

const set = new Set(['mkimq', 'mkimq.com'])
set.delete('mkimq')

使用 clear 删除所有元素

const set = new Set(['mkimq', 'mkimq.com'])
set.clear()

数组转换

可以使用点语法 或 Array.form 静态方法将Set类型转为数组,这样就可以使用数组处理函数了

const set = new Set(['mkimq', 'mkimq.com'])

console.log([...set])
console.log(Array.from(set))

移除Set中大于5的数值

let mk = new Set('123456789')
mk = new Set([...mk].filter(item => item < 5))
console.log(mk)

去除重复

去除字符串重复

console.log([...new Set('mkimq.com')].join(''))

去除数组重复

console.log(...new Set([1, 2, 3, 4, 1, 2, 3, 4]))

遍历数据

使用 keys()/values()/entries() 都可以返回迭代对象,因为set类型只有值所以 keys与values 方法结果一致。

const set = new Set(['mkimq', 'mkimq.com'])

console.log(set.values())
console.log(set.keys())
console.log(set.entries())

可以使用 forEach 遍历Set数据,默认使用 values 方法创建迭代器。

为了保持和遍历数组参数统一,函数中的value与key是一样的。

const set = new Set(['mkimq', 'mkimq.com'])
set.forEach((item, key) => console.log(item, key))

也可以使用 forof 遍历Set数据,默认使用 values 方法创建迭代器

const set = new Set(['mkimq', 'mkimq.com'])

for (const iterator of set) {
    console.log(iterator)
}

交集

获取两个集合中共同存在的元素

const mk = new Set(['mkimq', 'mkimq.com'])
const mk2 = new Set(['mkimq', 'https://www.mkimq.com'])

const arr = new Set(
    [...mk].filter(item => mk2.has(item))
)

差集

在集合mk中出现但不在集合mk2中出现元素集合

const mk = new Set(['mkimq', 'mkimq.com'])
const mk2 = new Set(['mkimq', 'https://www.mkimq.com'])

const arr = new Set(
    [...mk].filter(item => !mk2.has(item))
)

并集

将两个集合合并成一个新的集合,由于Set特性当然也不会产生重复元素。

const mk = new Set(['mkimq', 'mkimq.com'])
const mk2 = new Set(['mkimq', 'https://www.mkimq.com'])

console.log([...new Set([...mk, ...mk2])])

WeakSet

结构同样不会存储重复的值,它的成员必须只能是对象类型的值。

  • 垃圾回收不考虑WeakSet,即被WeakSet引用时引用计数器不加一,所以对象不被引用时不管WeakSet是否在使用都将删除
  • 因为WeakSet 是弱引用,由于其他地方操作成员可能会不存在,所以不可以进行forEach( )遍历等操作
  • 也是因为弱引用,WeakSet 结构没有keys( ),values( ),entries( )等方法和size属性
  • 因为是弱引用所以当外部引用删除时,希望自动删除数据时使用 WeakMap

声明定义

以下操作由于数据不是对象类型将产生错误

错误示范

new WeakSet(['mkimq', 'mkimq.com'])
new WeakSet('mkimq')

正确示范

// WeakSet的值必须为对象类型
new WeakSet([['mkimq'],['mkimq.com']])

// 将DOM节点保存到WeakSet
document.querySelectorAll('button').forEach(item => Wset.add(item))

基本操作

下面是WeakSet的常用指令

const weakSet = new WeakSet()
const arr = [1]

// 添加
weakSet.add(arr)

// 删除
weakSet.delete(arr)

// 检索判断
weakSet.has(arr)

垃圾回收

WeaSet保存的对象不会增加引用计数器,如果一个对象不被引用了会自动删除。

  • 下例中的数组被 arr 引用了,引用计数器+1
  • 数据又添加到了 mk 的WeaSet中,引用计数还是1
  • 当 arr 设置为null时,引用计数-1 此时对象引用为0
  • 当垃圾回收时对象被删除,这时WakeSet也就没有记录了
const mk = new WeakSet()
let arr = [1]

mk.add(arr)
console.log(mk.has(arr))

arr = null
console.log(mk)
贡献者: mankueng