成员或键值只能是对象

const weakset = new WeakSet()

weakset.add(1) // TypeError: Invalid value used in weak set
const weakmap = new WeakMap()

weakmap.set(1, {}) // TypeError: Invalid value used as weak map key

对成员或键值的引用是弱引用

什么是强引用?

let a = { age: 21 } 
const set = new Set()
set.add(a)
a = null
console.log('set:',set) // set: Set { { age: 21 } }

        a 对 { age: 21 } 这个值实际就是一个强引用。

        set也存在一个对{ age: 21 }的强引用。当把a的引用释放后。通过set一样能查询到这个对象。

      因为set存在对它的引用,导致GC并未回收它,它实际还存在于heap内存中。

弱引用的特点

let a = { age: 21 } 
const weakset = new WeakSet()
weakset.add(a)
a = null
// 浏览器中无法手动操作GC,使用定时器等待一段时间让GC自动回收。
setTimeout(() => {
  console.log('weakset:',weakset) // weakset: WeakSet {  }
}, 5000) 

        可以看到弱引用实际不会被看成引用标记。当a的引用被释放后,等待下一次GC就会自动把{ age: 21 }这个对象回收。

        WeakSet的出现让开发者在使用Set存储对象时无需当心内存泄漏的问题。WeakMap也是如此。只是有一点小差异,WeakMap仅仅只是针对于键值。

无法迭代

const weakset = new WeakSet()
const obj1 = {}
const obj2 = {}

weakset.add(obj1)
weakset.add(obj2)
// TypeError: weakset is not iterable
for(let v of weakset){
  console.log(v)
}

        基于弱引用和GC回收机制的原因, WeakSet 和 WeakMap 无法被迭代,因为GC是穿插在代码片段中运行的。很可能元素刚被遍历到,成员就取不到了。