set 对 null 和 undefined 完全去重且互不干扰,严格遵循 samevaluezero 规则:null === null、undefined === undefined 为 true,但 null !== undefined;常见“丢失”实为外部操作导致,非 set 本身问题。

JavaScript 中 Set 本身对 undefined 和 null 是完全去重的,不会“遗漏”或“误删”——它们各自被视为独立、合法的值,且严格遵循 SameValueZero 比较规则。真正的问题往往出在使用方式或预期偏差上:比如误以为 undefined 被过滤了,其实是它根本没被加进 Set;或者混淆了“空值未参与构造”和“被 Set 主动丢弃”。
Set 对 null 和 undefined 的行为是确定且符合直觉的
Set 使用 SameValueZero(类似 ===,但 NaN === NaN 为 true)判断重复。而 null === null 和 undefined === undefined 都为 true,null !== undefined,因此:
-
null只与另一个null视为重复 -
undefined只与另一个undefined视为重复 -
null和undefined互不冲突,可同时存在
✅ 示例验证:
s.size // → 4(null、undefined、0 各一个,重复项被忽略)
Array.from(s) // → [null, undefined, 0]
常见“丢失”场景及原因
所谓“undefined 没了”“null 被吞了”,通常不是 Set 的问题,而是数据源或操作环节导致:
-
数组解构或展开时跳过空位:稀疏数组
[1, , 3]展开后变成[1, undefined, 3],但若用filter(Boolean)或map(x => x && ...)预处理,undefined和null会被转为 false 而过滤掉 -
对象属性访问返回 undefined,但未显式加入 Set:例如
arr.map(x => x?.id)得到[1, undefined, 2],若后续又做了.filter(v => v != null),就主动剔除了undefined -
JSON 序列化/反序列化丢失:JSON 不支持
undefined,JSON.parse(JSON.stringify([...]))会把undefined变成null或直接省略,再塞进 Set 就失真了
需要保留 null/undefined 时的稳妥写法
如果业务逻辑明确要求 null 和 undefined 必须作为有效值参与去重,关键在于:绕过所有隐式类型转换和过滤步骤,直接将原始值传入 Set。
- 避免用
.filter(Boolean)、.filter(x => x)、.filter(x => x != null)等预处理 - 用
Array.from(new Set(arr))代替[...new Set(arr)](二者等价,但前者语义更清晰) - 若需兼容旧环境或特殊结构,可手动归一化:
arr.map(x => x === undefined ? 'UNDEFINED' : x === null ? 'NULL' : x),去重后再还原(仅当必须规避原生值时才考虑)
对比 Map 与 Object 处理空值的差异(辅助理解)
Set 的行为其实比 Object 更可靠:
-
Object键会强制转字符串:{ null: 1, undefined: 2 }实际是{ 'null': 1, 'undefined': 2 },且obj[null]等价于obj['null'] -
Map支持任意类型作键,map.set(null, 1); map.set(undefined, 2)完全独立,这点和Set一致 - 所以当需要区分
null/undefined且保持原值语义时,Set和Map是更安全的选择
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











