set实现数组并集、交集、差集:并集用[...new set([...arr1,...arr2])],交集用arr1.filter(x=>setb.has(x)),差集用arr1.filter(x=>!setb.has(x))并视需去重;引用类型需序列化或提取id处理。

用 Set 实现数组并集:去重 + 合并
直接用 Set 构造器把两个数组展开合并,天然去重。注意:原始顺序不保留,且只适用于基础类型(如数字、字符串);引用类型(对象、数组)会被当作不同元素处理。
- 写法:
[...new Set([...arr1, ...arr2])] - 如果需保持
arr1的顺序在前、arr2中新元素补在后,改用:[...new Set(arr1), ...arr2.filter(x => !arr1.includes(x))] - 性能提示:对大数组慎用
includes,它 O(n) 查找;可先转new Set(arr1)再用has(),提升到 O(1)
用 Set 求交集:filter + has 是关键
交集本质是“在 A 里,且也在 B 里”。把其中一个数组转成 Set,再用 filter 配合 has() 判断,比嵌套循环快得多。
- 标准写法:
arr1.filter(x => setB.has(x)),其中setB = new Set(arr2) - 注意重复项:如果
arr1有重复,结果也会保留这些重复 ——Set只用于查找,不自动去重结果 - 若要结果无重复,包一层:
[...new Set(arr1.filter(x => setB.has(x)))] - 错误示范:
arr1.filter(x => arr2.includes(x))—— 对万级数组可能卡顿,includes是线性扫描
用 Set 做差集(A - B):别漏掉去重逻辑
差集即“A 中有、B 中没有”的元素。和交集类似,但逻辑取反。容易忽略的是:A 自身若有重复,是否要保留?多数场景要的是“唯一差集”,所以通常需要最终去重。
- 基础差集(保留 A 原重复):
arr1.filter(x => !setB.has(x)) - 去重差集(推荐):
[...new Set(arr1.filter(x => !setB.has(x)))] - 反向差集(B - A)只需调换变量:
[...new Set(arr2.filter(x => !setA.has(x)))] - 陷阱:
Set不能直接减,setA - setB是 NaN —— JavaScript 没有集合运算符,必须靠数组方法桥接
复杂类型(对象/数组)怎么处理?Set 失效了
Set 判等用的是 Object.is(),所以两个结构相同但内存地址不同的对象,在 Set 里就是不同元素。这时不能直接用 new Set(arr),得降维。
- 简单方案:用 JSON 字符串化键名(仅限可序列化、无函数/undefined/循环引用的数据):
new Set(arr.map(x => JSON.stringify(x))) - 更稳方案:提取唯一标识字段(如
id),构造Set存 ID,再做filter:const idsB = new Set(arr2.map(x => x.id)); arr1.filter(x => !idsB.has(x.id)) - 千万别用
arr1.filter(x => !arr2.find(y => _.isEqual(x, y)))(依赖 Lodash)—— 每次都全量遍历,O(n²),大数据量明显卡
实际用的时候,最常被绕过的其实是“要不要去重结果”和“原始顺序是否重要”这两个判断点。Set 本身不维护插入顺序以外的语义,所有操作都要主动想清楚这两层。










