Set 的 add() 和 has() 是 JavaScript 中最轻量高效的数据存在性检测方式;add() 支持链式调用、自动去重、按引用判断对象、NaN 视为相同值;has() 基于哈希实现 O(1) 查找,严格相等比较,适用于防重提交、白名单校验等场景。

用 Set 的 add() 和 has() 配合,是 JavaScript 中最轻量、最高效的数据存在性检测方式——不遍历、不重复、接近常数时间。
add():添加唯一值,支持链式调用
它只负责“存”,但自带防重逻辑:
- 传入任意类型(数字、字符串、布尔、
null、undefined、Symbol、对象、函数)都有效 - 重复值不会报错,也不会改变 Set,例如
s.add(5).add(5)后仍只有 1 个5 - 返回 Set 本身,可连续写:
new Set().add('a').add('b').add('c') - 注意对象和数组按引用判断:两个
{x:1}是不同元素;同一个对象变量反复 add 只生效一次 -
NaN是特例:虽然NaN === NaN为 false,但 Set 把所有NaN当作相同值处理
has():O(1) 查找,比数组快得多
它只回答“有没有”,不关心位置或数量:
- 内部基于哈希查找,无论 Set 有 10 个还是 10 万个元素,耗时基本一致
- 对比
arr.includes(x)(平均 O(n))或arr.indexOf(x) !== -1,set.has(x)在大数据量下优势明显 - 判断依据是严格相等
===,所以set.has("1")和set.has(1)互不影响 - 对对象同样按引用判断:
set.has(obj)返回 true,仅当传入的是当初add(obj)的那个变量
典型组合用法:防重提交 / 去重缓存 / 快速白名单校验
比如表单防重复提交:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- 定义
const submittedIds = new Set() - 点击提交前:
if (submittedIds.has(id)) return; submittedIds.add(id)
再比如权限白名单检查:
const allowedRoles = new Set(['admin', 'editor'])if (allowedRoles.has(user.role)) { /* 允许操作 */ }
不需要先转数组、不用 filter 或 findIndex,一行 has() 就能闭环判断。
小提醒:别误用 has 检查“子集”
has() 只查单个值。若要判断一个 Set 是否包含另一个 Set 的全部元素(即子集关系),需手动遍历:
[...baseSet].every(item => targetSet.has(item))- 或用 for…of 循环 + 提前退出,避免全量遍历










