JavaScript Set 使用 SameValueZero 算法判断重复,NaN 和 ±0 被视为相同,对象按引用比较,无键概念,仅存值,不支持下标访问,去重对象数组需手动处理唯一标识。

JavaScript Set 是一个内置构造函数,用来创建元素唯一、无序的集合。它不基于键值对,也不允许重复值——哪怕两个值在 JavaScript 中“相等”,Set 也会按 SameValueZero 算法判断是否重复,这意味着 NaN 和 NaN 被视为相同,而 +0 和 -0 也被视为相同(这点和 Object 的键不同)。
Set 如何判断值是否重复
Set 内部使用 SameValueZero 比较算法,不是 ===,也不是 Object.is()(虽然非常接近)。关键行为包括:
-
NaN只会被存一次:const s = new Set([NaN, NaN]); s.size // 1
-
+0和-0被视为同一个值:const s = new Set([+0, -0]); s.size // 1
- 对象即使内容相同,也视为不同(因为引用不同):
const a = {x: 1}; const b = {x: 1}; new Set([a, b]).size // 2 - 原始值与对应包装对象被视为不同:
new Set([1, new Number(1)]).size // 2
Set 存储的是值本身,不是键名
和 Map 或普通对象不同,Set 没有“键”概念。它只维护一个值列表,每个值既是“键”也是“值”。这带来几个实际影响:
- 不能用
set[key]访问,必须用set.has(value)查询存在性 - 没有类似
Object.keys()的原生键枚举方法;遍历靠for...of、set.values()或展开运算符[...set] - 添加重复值不会报错,也不会覆盖,只是静默忽略:
const s = new Set(); s.add(42); s.add(42); s.size // 1
常见误用:想用 Set 去重对象数组?得自己处理
直接把对象放进 Set 不会按属性去重,因为对象比较看引用。如果要按结构去重,必须先序列化或提取唯一标识:
立即学习“Java免费学习笔记(深入)”;
- 错误写法(无效去重):
const arr = [{id: 1}, {id: 1}]; const unique = [...new Set(arr)]; // length === 2 - 正确思路之一(用 ID 字符串做中介):
const arr = [{id: 1}, {id: 1}, {id: 2}]; const seen = new Set(); const unique = arr.filter(item => { if (seen.has(item.id)) return false; seen.add(item.id); return true; }); - 注意:JSON.stringify() 不可靠(属性顺序、undefined、function、Symbol 会被忽略或报错)
真正容易被忽略的是:Set 的“唯一性”完全依赖运行时的值表示,不是开发者语义上的“相同”。一旦你混用原始值和包装对象、或依赖对象结构而非引用,就很容易以为去重了,其实没生效。










