Set避坑:别把它当数组用

Set避坑最常见的问题,不是语法记不住,而是把它当成“高级数组”。它确实能去重、查找快,但顺序、引用、序列化、业务语义都有坑。下面按对比拆开讲,少踩几个线上雷。

Set vs Array:去重爽,但不是万能容器

Array 适合保存一串有位置、有重复、有下标意义的数据,比如订单明细、聊天记录、表格行。Set 适合保存“唯一集合”,比如用户ID、标签ID、已选中的权限码。很多 set避坑 都卡在这一步:明明数据有顺序和重复意义,却硬塞进 Set。

举个真实场景:商品规格里有颜色数组 ["红", "红", "蓝"],两个“红”可能来自不同供应商或库存批次。你用 new Set() 一去重,页面看着清爽,库存统计直接错。Set 去重只应该用于“重复没有业务价值”的场景。

has vs includes:快不快,取决于数据量

Set.has() 平均查找复杂度接近 O(1),Array.includes() 是 O(n)。听起来 Set 赢麻了,但别急。几十个元素时,差距几乎体感不到,甚至构建 Set 的成本会把优势吃掉。

我的习惯是:一次性查 1 次、数组长度小于几百,直接 includes,代码更直。要查很多次,比如 1万个商品ID里筛选用户收藏的2000个ID,把收藏ID先转 Set,再循环 has,这才是 Set 的主场。

想要完整资源?

会员专享,海量内容

立即查看 →

值去重 vs 引用去重:对象数组别想太美

Set 对基本类型很友好:1、"1"、true 都按值区分;NaN 也能被识别为同一个 NaN。但对象就不一样了,它看的是引用地址,不看内容。

new Set([{id:1},{id:1}]) 的长度是 2,不是 1。这是前端新人最容易踩的 set避坑。对象去重别直接扔 Set,要用 Map:遍历数组,把 id 当 key,最后取 values。这样才是按业务字段去重。

顺序 vs 排序:Set保留插入顺序,不负责排序

Set 会保留插入顺序,这点很好用:你按点击顺序收集标签,遍历时就是点击顺序。但它不会自动排序,也没有 sort 方法。想排序,得 [...set].sort() 再处理。

还有一个细节:delete 后再 add,同一个值会跑到最后。比如 Set 里是 A、B、C,删掉 B 再加 B,顺序变成 A、C、B。如果你的 UI 依赖顺序,这个小动作会让列表跳来跳去。

JSON vs Set:传接口前一定要转换

Set 不能被 JSON.stringify 正常序列化。JSON.stringify(new Set([1,2])) 得到的是 {},不是 [1,2]。如果你没注意,接口请求体可能悄悄变空,后端还以为你没选权限。

靠谱做法是传输前转数组:Array.from(mySet) 或 [...mySet]。接口回来如果是数组,再按需要转 Set。记住一句话:Set 是运行时工具,不是接口数据格式。这个边界守住,能少很多玄学 bug。

常见问题

Set可以完全替代数组吗?
不可以。Set 没有下标、没有 map/filter 那套数组语义,也不适合保存重复项。它适合唯一集合,数组适合列表数据。
对象数组用Set为什么去不了重?
因为 Set 比较对象时看引用地址,不看对象内容。两个 {id:1} 长得一样,但引用不同,所以会被当成两个元素。
Set传给后端为什么变成空对象?
JSON.stringify 无法直接序列化 Set。传接口前要转成数组,比如 [...set],后端才会收到正常列表。

获取完整内容

加入会员,海量资源任你看

立即进入 →