WeakSet
WeakSet 结构与 Set 类似,也是不重复的值的集合。
成员都是数组和类似数组的对象,WeakSet 的成员只能是对象,而不能是其他类型的值。
若调用 add() 方法时传入了非数组和类似数组的对象的参数,就会抛出错误。
const b = [1, 2, [1, 2]]
new WeakSet(b) // Uncaught TypeError: Invalid value used in weak set
- 成员都是弱引用,可以被垃圾回收机制回收,可以用来保存 DOM 节点,不容易造成内存泄漏。
- WeakSet 不可迭代,因此不能被用在 for-of 等循环中。
- WeakSet 没有 size 属性。
WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。
WeakMap
WeakMap 结构与 Map 结构类似,也是用于生成键值对的集合。
- 只接受对象作为键名(null 除外),不接受其他类型的值作为键名
- 键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的
- 可被垃圾回收,不能遍历,也没有 size 属性,方法有 get、set、has、delete
注意
WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用(如下)
const wm = new WeakMap();
let key = {};
let obj = {foo: 1};
wm.set(key, obj);
obj = null;
wm.get(key)
// Object {foo: 1}
上面代码中,键值 obj 是正常引用。所以,即使在 WeakMap 外部消除了obj 的引用,WeakMap 内部的引用依然存在。(注意和下面的对比)
const wm1 = new WeakMap();
let obj1 = {a: 1};
let value1 = 2;
wm1.set(obj1, value1);
wm1.get(obj1); // 2
obj1 = {}; 或者 obj1 = null;
wm1.get(obj1); // undefined
wm1; (结果如下图)
把键名 obj1 赋空值之后,不可以通过 wm1.get(obj1); 获取到正确的键值 value1
但是打印 wm1 发现,之前保存的 键名和键值 依旧存在且正确
弱引用
WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中
- 弱引用:垃圾回收机制有一套自己的回收算法,我们都知道一个函数执行完成后该函数在调用栈中创建的执行上下文会被销毁,这里说的销毁,其实指的就是执行上下文中环境变量、词法变量中的数据存储所占据的内存空间被垃圾回收机制所回收,那么垃圾回收机制不考虑 WeakSet 对该对象的引用 是不是就意味着垃圾回收机制不会回收 WeakSet 对象里面的数据所占据的内存呢? 不!不是的!代码是最好的解释
let obj = {name:'kirara'}
let ws = new WeakSet()
ws.add(obj)
obj = null
console.log(ws) //WeakSet{}
用 ws 中存放一个对象,然后再将该对象置为 null,(一个变量被置为 null,就意味着这个变量的内存可以被回收了)只要 WeakSet 结构中的对象不再需要被引用,那么 WeakSet 就直接为空了,就意味着 WeakSet 中的数据所占据的内存被释放了, Set 结构不会如此(如下)
let obj = {name:'kirara'}
let s =new Set()
s.add(obj)
obj = null
console.log(s)
// value: {name: "kirara"}
WeakSet 使用场景
储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏
<div id="wrap">
<button id='btn'>确定</button>
</div>
<script>
let wrap = document.getElementById('wrap')
let btn = document.getElementById('btn');
// 假如想给这个btn打上“禁用”标签,选择把它存放在 WeakSet结构中
const disabledElements = new WeakSet();
disabledElements.add(btn);
btn.addEventListener('click', () => {
wrap.removeChild(btn)
})
</script>
这里当 button 被移除,disabledElements 中的内容会因为是弱引用而直接变成空
也就是 disabledElements 被垃圾回收掉了其中的内存,避免了一个小小的内存泄漏的产生
文章如有错误,恳请大家提出问题,本人不胜感激 。 不懂的地方可以评论,我都会 一 一 回复
文章对大家有帮助的话,希望大家能动手点赞鼓励,大家未来一起努力 长路漫漫,道阻且长