如何为 JavaScript Set 自定义对象相等性

新手上路,请多包涵

新的 ES 6 (Harmony) 引入了新的 Set 对象。 Set 使用的身份算法类似于 === 运算符等不太适合比较对象:

 var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]

如何自定义 Set 对象的相等性以便进行深度对象比较?有没有类似 Java equals(Object) 东西?

原文由 czerny 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 822
2 个回答

更新 32022

目前有一个 提议 将 Records 和 Tuples(基本上是不可变的对象和数组)添加到 Javascript。在该提案中,它使用 ===!== 提供记录和元组的直接比较,它比较值,而不仅仅是对象引用和与此答案相关的 SetMap 对象将在键比较/查找中使用 Record 或 Tuple 的 ,这将解决此处所要求的问题。

由于 Records 和 Tuples 是不可变的(无法修改)并且因为它们很容易按值进行比较(通过它们的内容,而不仅仅是它们的对象引用),它允许 Maps 和 Sets 使用对象内容作为键和明确提出的规范将此功能命名为 Sets 和 Maps。

这个原始问题要求 Set 比较的可定制性,以支持深度对象比较。这不建议 Set 比较的可定制性,但如果您使用新的 Record 或 Tuple 而不是 Object 或 Array,它直接支持深度对象比较,从而解决这里的原始问题。

请注意,该提案已于 2021 年年中进入第二阶段。它最近一直在向前推进,但肯定没有完成。

Mozilla 在这个新提案上的工作可以在 这里 追踪。


原始答案

ES6 Set 对象没有任何比较方法或自定义比较扩展性。

.has() , .add().delete() 方法只适用于它是相同的实际对象或意味着不具有相同的原始值或者只替换那个逻辑。

You could presumably derive your own object from a Set and replace .has() , .add() and .delete() methods with something that did a deep object comparison首先要查找该项目是否已经在 Set 中,但性能可能不会很好,因为底层 Set 对象根本没有帮助。在调用原始 .add() 之前,您可能只需要对所有现有对象进行强力迭代以使用您自己的自定义比较找到匹配项。

以下是 本文中的一些信息以及对 ES6 功能的讨论

5.2 为什么我不能配置映射和集合如何比较键和值?

问题:如果有一种方法可以配置哪些映射键和哪些集合元素被认为是相等的,那就太好了。为什么没有?

答:该功能已被推迟,因为难以正确有效地实施。一种选择是将回调传递给指定相等性的集合。

Java 中可用的另一个选项是通过对象实现的方法(Java 中的 equals())指定相等性。然而,这种方法对于可变对象是有问题的:一般来说,如果一个对象发生变化,它在集合中的“位置”也必须改变。但这不是 Java 中发生的事情。 JavaScript 可能会走更安全的路线,只对特殊的不可变对象(所谓的值对象)启用按值比较。按值比较意味着如果两个值的内容相等,则认为它们相等。原始值在 JavaScript 中按值进行比较。

原文由 jfriend00 发布,翻译遵循 CC BY-SA 4.0 许可协议

正如 jfriend00 的回答 customization of equality relation is probably not possible 中提到的。

以下代码概述了计算效率高(但内存昂贵)的 解决方法

 class GeneralSet {

    constructor() {
        this.map = new Map();
        this[Symbol.iterator] = this.values;
    }

    add(item) {
        this.map.set(item.toIdString(), item);
    }

    values() {
        return this.map.values();
    }

    delete(item) {
        return this.map.delete(item.toIdString());
    }

    // ...
}

每个插入的元素都必须实现 toIdString() 返回字符串的方法。当且仅当它们的 toIdString 方法返回相同的值时,两个对象才被认为是相等的。

原文由 czerny 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题