直接用 [...new set(arr)] 可正确区分 1 和 true、0 和 false,因 set 使用 samevaluezero 算法(1 !== true),无需额外处理;若需按数值语义合并(如 true 与 1 视为重复),则须自定义键生成逻辑。

JavaScript 数组去重时,布尔值(true/false)和数字(如 1/0)混杂会引发隐式类型转换问题——因为 1 == true、0 == false 为真,但它们是不同类型。若用简单去重方法(如 Set 或 filter + indexOf),默认只做值比较,容易误删或保留错误项。关键是要**区分原始类型和值**,而非仅依赖相等性。
用 Set + 类型感知的键生成
单纯 new Set(arr) 无法区分 1 和 true,因为 Set 使用 SameValueZero 算法(与 === 类似,但 0 === -0、NaN === NaN)。而 1 !== true,所以原生 Set 实际上**能正确保留两者**。验证如下:
const arr = [1, true, 0, false, 2, '1'];console.log([...new Set(arr)]); // [1, true, 0, false, 2, "1"]
注意:1 和 true 都保留了,因为 1 !== true;同理 0 !== false。所以对纯布尔+数字混杂场景,直接用 Set 是安全且最简方案。
需要严格按“数值语义”合并时(如 1 和 true 视为重复)
若业务逻辑要求把 true 当作 1、false 当作 0 去重(即语义等价),就不能依赖 ===,需自定义判重逻辑:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 遍历数组,对每个元素生成唯一键:对布尔值转成对应数字(
true → "1-boolean",false → "0-boolean"),对数字则用"${num}-number" - 用 Map 或对象记录已出现的键,跳过重复键对应的原值
示例代码:
function dedupeByValue(arr) { const seen = new Set(); return arr.filter(item => { let key; if (typeof item === 'boolean') { key = item ? '1-boolean' : '0-boolean'; } else if (typeof item === 'number') { key = `${item}-number`; } else { key = JSON.stringify(item); // 兜底其他类型 } if (seen.has(key)) return false; seen.add(key); return true; });}dedupeByValue([1, true, 0, false, 2]); // [1, 0, 2] —— true/1 合并,false/0 合并
避免 toString() 或 +item 等隐式转换陷阱
常见错误写法:arr.filter((x, i) => arr.indexOf(x) === i) 或 [...new Set(arr.map(String))],这些会触发强制转换:
-
String(true) === "true",String(1) === "1"→ 不冲突,但失去原始类型 -
+true === 1,+false === 0→ 若先转数字再 Set,true和1就被当成同一项
除非明确要丢弃类型信息,否则不要对原始数组做全局类型转换后再去重。
总结:按需求选策略
默认推荐:直接用 [...new Set(arr)] —— 它天然区分 1 和 true,代码简洁,性能好,符合 JS 类型系统直觉。
语义合并需求:用自定义键生成 + Set 过滤 —— 显式控制“什么算重复”,避免隐式转换副作用。
永远避开:先统一转字符串或数字再 Set —— 会破坏原始数据类型,引入难以调试的歧义。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










