Symbol去重无效因每个Symbol引用唯一,Set基于SameValueZero算法只对同一引用判等;按描述去重需用description属性配合Map缓存;对象数组中含Symbol属性时应提取其值用Map判重,禁用JSON.stringify。

JavaScript 数组去重时,Symbol 类型天然不会被重复去除,因为每个 Symbol 值都是唯一且不可复用的——哪怕描述相同,`Symbol('a') !== Symbol('a')`。所以常规去重方法(如 Set、filter + indexOf)对 Symbol 元素“无效”,它们会原样保留所有 Symbol,不认为彼此重复。
为什么 Set 无法去重 Symbol?
Set 的去重逻辑基于 SameValueZero 算法,它对 Symbol 的处理是:只要两个值是同一个 Symbol 引用(即同一内存地址),才视为相等;而每次调用 Symbol() 都创建新引用。因此:
-
const s1 = Symbol('x'); const s2 = Symbol('x');→s1 !== s2 -
new Set([s1, s2])→ 包含两个元素,不会合并
想按描述去重 Symbol 怎么办?
若业务场景中希望“描述相同即视为重复”(例如统一用 Symbol('id') 标识字段),需手动提取描述字符串做映射:
- 用
Symbol.prototype.description获取描述(注意:Symbol.for('key')创建的全局 Symbol 也支持此属性) - 借助 Map 或对象缓存已见的 description,跳过重复项
示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
const arr = [Symbol('a'), Symbol('b'), Symbol('a'), Symbol.for('c')];const seen = new Set();
const unique = arr.filter(sym => {
const desc = sym.description;
if (desc === undefined) return true; // 未描述的 Symbol 视为不可去重
if (seen.has(desc)) return false;
seen.add(desc);
return true;
});
// 结果保留第一个 Symbol('a'),第二个被过滤
对象数组里含 Symbol 属性,怎么去重?
如果数组元素是对象,且靠 Symbol 属性判重(如 { [Symbol('uid')]: 123 }),不能依赖 JSON.stringify(它会忽略 Symbol 属性)。正确做法是:
- 用 Map 缓存 Symbol 属性的值作为键(前提是该值是基础类型或可序列化)
- 或用
Object.getOwnPropertySymbols()提取并比对 Symbol 键对应的值
简单策略:提取目标 Symbol 属性值,用 Map 去重:
const arr = [{ name: 'A', [Symbol('id')]: 1 },
{ name: 'B', [Symbol('id')]: 2 },
{ name: 'C', [Symbol('id')]: 1 }
];
const map = new Map();
const unique = arr.filter(item => {
const sym = Object.getOwnPropertySymbols(item).find(s => s.description === 'id');
if (!sym) return true;
const val = item[sym];
if (map.has(val)) return false;
map.set(val, true);
return true;
});
注意事项
Symbol 去重本质是语义问题,不是技术限制:
- 直接比较 Symbol 引用永远不等,这是设计使然
- 按 description 去重需确认业务是否允许忽略 Symbol 创建方式差异(如
Symbol()vsSymbol.for()) - 涉及 Symbol 的对象去重,务必避免 JSON.stringify,它会丢失 Symbol 信息

















