symbol数组去重无需特殊处理,因set基于samevaluezero算法天然支持:不同symbol实例即使描述相同也视为不同元素,仅同一引用会被去重;对象数组需手动提取symbol属性配合map或filter实现。

JS 中处理包含 Symbol 类型的数组去重,关键在于理解 Symbol 的特性:每个 Symbol 值都是唯一且不可重复的,即使描述相同(如 Symbol('a') 和 Symbol('a'))也互不相等。因此,Symbol 能被 Set 正确保留并去重——这不是“需要特殊处理”,而是它天然适配 Set 的去重逻辑。
Set 可直接处理 Symbol(推荐)
因为 Set 判断唯一性时使用的是 SameValueZero 算法,而该算法对 Symbol 的比较是严格引用相等(即两个 Symbol 永远不等,除非是同一个变量赋值)。这意味着:
- 不同调用生成的 Symbol(哪怕描述一致)会被视为不同元素,保留在结果中;
- 同一 Symbol 实例多次出现,会被 Set 自动去重为一个。
示例:
const arr = [1, Symbol('id'), 'name', Symbol('id'), Symbol('key'), Symbol('id')];<br>const unique = [new Set(arr)];<br>console.log(unique); // [1, Symbol('id'), 'name', Symbol('key')]<br>// 注意:只有第三个 Symbol('id') 是复用第一个变量的引用才被去重;<br>// 若是三次独立调用 Symbol('id'),则三个都会保留
注意 Symbol 描述不参与相等判断
不要误以为写相同描述就能“合并” Symbol。以下代码中三个 Symbol 全部保留:
const arr = [Symbol('uid'), Symbol('uid'), Symbol('uid')];<br>console.log([new Set(arr)]); // [Symbol('uid'), Symbol('uid'), Symbol('uid')]
这是因为每次 Symbol('uid') 都创建了全新、唯一的值。若想复用,必须提前定义变量:
const uid = Symbol('uid');<br>const arr = [uid, uid, uid];<br>console.log([new Set(arr)]); // [Symbol('uid')]
对象数组含 Symbol 属性时需手动处理
如果数组元素是对象,且你想按某个 Symbol 类型的属性去重(比如 { [Symbol('id')]: 123 }),Set 无法自动识别,需配合 findIndex 或 Map:
- 用
Map存储已见的 Symbol 属性值,避免深比较; - 遍历对象数组,提取目标 Symbol 键对应的值,查 Map 是否存在,不存在则加入结果并记录;
- 注意:Symbol 作为对象键不可枚举,需用
Object.getOwnPropertySymbols()获取。
示例(按 Symbol('id') 字段去重):
const symId = Symbol('id');<br>const users = [<br> { name: 'A', [symId]: 1 },<br> { name: 'B', [symId]: 2 },<br> { name: 'C', [symId]: 1 } // 与第一个 id 相同<br>];<br><br>const seen = new Set();<br>const uniqueUsers = users.filter(user => {<br> const id = user[symId];<br> if (seen.has(id)) return false;<br> seen.add(id);<br> return true;<br>});
兼容旧环境时避免依赖 Set
若需支持 IE 或极老运行时,不能用 Set,此时 Symbol 的去重逻辑需显式实现:
- 可用
Array.prototype.filter()+Array.prototype.findIndex(); - 但注意:Symbol 之间只能用
===判断,不能用==或字符串转换; - 对基本类型混合 Symbol 的数组,建议统一用
Object.is()比较,它能正确处理 Symbol、NaN、+0/-0 等边界情况。











