WeakSet 能不能用来监听 DOM 元素的销毁?
我在做一个组件库,想用 WeakSet 来跟踪哪些 DOM 元素已经被移除了,但发现好像没法判断元素是否还在页面上。WeakSet 不是自动清理的吗?为什么我没法知道它什么时候被清掉了?
比如我这样写:
const observedNodes = new WeakSet();
function observe(node) {
observedNodes.add(node);
}
// 后面想检查 node 是否还在 observedNodes 里
// 但即使 node 已经从 DOM 移除,observedNodes.has(node) 还是 true
是不是我对 WeakSet 的理解有误?它根本不能用来做这种“监听销毁”的事情?
先说说 WeakSet 的特性
WeakSet 的核心特点是"弱引用",也就是说它不会阻止垃圾回收。当一个对象只被 WeakSet 引用,而没有被其他地方引用时,GC 会把它回收掉,WeakSet 里就找不到它了。
但问题在于:GC 什么时候运行是浏览器决定的,你无法监听也无法控制。而且 DOM 元素被从页面移除后,它仍然存在于内存中啊,除非你也断开所有对它的引用,否则它不会被回收。你只是把 node 从 DOM 移除了,又不是把它置为 null,observedNodes 依然持有对它的引用,所以 has 肯定还是 true。
那怎么监听 DOM 元素的销毁呢
正确的做法是用 MutationObserver,这货就是专门用来监听 DOM 变化的。
MutationObserver 会实时通知你 DOM 节点什么时候被移除了,这才是你想要的功能。
总结一下
WeakSet 适合的场景是:你想让某些对象在没有被其他地方引用时自动被回收(比如缓存一些不重要的数据)。但它不适合用来"监听"某个东西,因为 WeakSet 本身不提供任何通知机制。
做 DOM 销毁监听,用 MutationObserver 就对了。