set可直接存储dom节点且天然去重,因基于内存引用判等;weakset适合短期节点避免内存泄漏;展开语法[...new set(nodelist)]可快速去重。

Set 可以直接存储 DOM 节点,并天然保证不重复——因为节点是对象,Set 使用 Object.is() 判等,而同一 DOM 元素在内存中只有一个引用,多次添加同一个节点不会重复存入。
DOM 节点作为 Set 元素的原理
DOM 节点是对象引用类型。当你把一个 <div> 元素传给 <code>add(),Set 记录的是该对象的内存地址。哪怕你反复写 set.add(btn) 十次,只要 btn 是同一个变量(指向同一个节点),Set 里最终只有一份。
- 不同节点即使内容相同,也是不同引用,会被视为不同元素
-
document.getElementById('a')和document.querySelector('#a')返回的是同一个节点,添加两次也只算一次 - 用
cloneNode()创建的新节点,哪怕结构完全一样,也是新引用,会独立存入
常见实用写法
比如监听多个按钮点击,只记录“被点过”的节点:
- 创建:
const clickedNodes = new Set(); - 添加:
clickedNodes.add(event.target);(event.target 是触发事件的 DOM 节点) - 判断是否点过:
if (clickedNodes.has(event.target)) { ... } - 统计数量:
clickedNodes.size就是已点过的唯一节点数
注意内存与 WeakSet 的取舍
普通 Set 对 DOM 节点保持强引用:只要 Set 存着它,即使该节点从页面中移除,也不会被垃圾回收。如果节点频繁增删、生命周期短(比如动态生成又销毁的弹窗按钮),长期持有可能导致内存泄漏。
这时更适合用 WeakSet:
const weakClicked = new WeakSet();- 同样支持
add()、has()、delete() - 但只接受对象(包括 DOM 节点)作值,且不阻止垃圾回收
- 缺点:不能遍历、没有
size、不能存原始值
小技巧:快速去重一组节点
比如获取所有 class 为 btn 的元素,但其中可能有重复(如多次调用 getElementsByClassName 或混用 querySelectorAll + 手动 push):
const uniqueBtns = Array.from(new Set(document.querySelectorAll('.btn')));- 或更简洁:
[...new Set(nodeList)];(利用展开语法自动转数组)











