Set对对象只比较内存地址而非属性值,因其内部使用SameValueZero算法(与===一致),不调用toString()或valueOf(),也不支持深度比较或自定义相等逻辑。
JavaScript 的
对对象不做“深度比较”,它只认内存地址——两个
字面量哪怕结构一模一样,也是两个独立对象,分配在不同内存位置,
判断为
,
就认为它们不重复。
根本原因:Set 依赖 SameValueZero 算法
内部用的是 SameValueZero 比较规则(与
基本一致,仅对
/
和
特殊处理)。该规则对对象只比较引用,不遍历属性、不递归检查嵌套值。所以:
包含两个元素
也包含两个元素
哪怕对象只有 1 层、1 个属性、全是基本类型,只要不是同一引用,就无法去重
为什么不能靠 toString() 或 valueOf() 干预?
完全不调用对象的
、
或任何自定义方法。这些方法在对象转字符串或数值运算时才起作用,而
或
过程中不会触发它们——这是常见误解来源。
所谓“深度限制”其实是根本没深度
“深度”在这里是误导性说法。
并非“限制在某一层”,而是压根没有设计深度逻辑。它不像 Java 的
那样允许重写
和
,也不像某些库提供比较器参数。它的行为是固定的、底层的、不可覆盖的。
验证方式很简单
只需两行代码就能确认:
第二行结果直接解释了第一行——
的判断依据就是
。
Set{a: 1}===falseSetSet===+0-0NaNnew Set([{x: 1}, {x: 1}])new Set([{}, {}])SettoString()valueOf()Set.has()add()SetHashSethashCode()equals()const s = new Set(); s.add({a: 1}); console.log(s.has({a: 1})); // falseconsole.log({a: 1} === {a: 1}); // falsehas()===