Set 默认区分数字1和字符串"1",因其底层使用SameValueZero算法(类似===),故1==="1"为false,两者被视为不同值;需按数值去重时应先统一类型再用Set。

JavaScript 中 Set 去重时,数字 1 和字符串 "1" 默认就是**被区分的**——这恰恰是它的正确行为,不是 bug,而是由 JS 的严格相等(===)和 SameValueZero 算法共同决定的。
Set 本身已天然区分类型
Set 判断是否重复,底层使用的是 SameValueZero 算法(与 === 高度一致,仅对 NaN === NaN 特殊处理)。这意味着:
-
1 === "1"是 false → Set 把它们当作两个不同值 -
1 === 1是 true → 第二个1会被自动丢弃 -
"1" === "1"是 true → 第二个"1"同样被丢弃
所以以下代码结果完全符合预期:
const arr = [1, "1", 1, "1", 2, "2"];const unique = Array.from(new Set(arr));
// → [1, "1", 2, "2"]
为什么有人觉得“没区分”?常见误解来源
问题往往不出在 Set,而出在其他环节:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
-
后端返回数据未规范类型:比如接口把数字 ID 当字符串返回(
"123"),前端又用parseInt或+混合处理,导致数组里同时存在123和"123",Set 正确保留两者,但业务上其实应统一为一种类型 -
手动转类型再塞进 Set 却忘了保持一致性:例如想“按数值去重”,却只对部分元素做了
Number()转换,造成逻辑混乱 -
误用 JSON.stringify + Map 做对象去重时,把原始值也一并序列化:比如
JSON.stringify(1)和JSON.stringify("1")都变成字符串,反而模糊了类型差异
需要按“数值意义”去重?那就先归一化类型
如果业务明确要求 1 和 "1" 视为重复(即按值语义而非类型语义),Set 不能直接做到,但可以配合预处理:
- 全部转成数字(适合纯数字场景):
Array.from(new Set(arr.map(x => Number(x)))) - 全部转成字符串(适合 ID 类字符串):
Array.from(new Set(arr.map(String))) - 更安全的数值归一化(避免
Number("abc") → NaN):
Array.from(new Set(arr.map(x => typeof x === 'number' ? x : parseInt(x, 10)).filter(Number.isFinite)))
小结:Set 的“区分”正是它的严谨之处
它不擅自猜测你的意图,而是忠实地按 JS 类型系统执行去重。你要的是类型安全,它给你;你要的是业务语义统一,你就得在进 Set 之前把数据理清楚。这种分离设计,让逻辑更可控、bug 更易定位。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










