更新 3/2022
目前有一个proposal https://github.com/tc39/proposal-record-tuple#usage-in-mapsetweakmapweakset将记录和元组(基本上是不可变的对象和数组)添加到 Javascript。在该提案中,它提供了使用记录和元组的直接比较===
or !==
它比较值,而不仅仅是对象引用并且与此答案相关Set
and Map
对象将使用value关键比较/查找中的记录或元组的信息,这将解决此处所要求的问题。
由于记录和元组是不可变的(无法修改),并且它们很容易通过值进行比较(通过它们的内容,而不仅仅是它们的对象引用),因此它允许映射和集合明确地使用对象内容作为键和建议的规范将此功能命名为“集合”和“地图”。
这个原始问题要求设置比较的可定制性,以支持深度对象比较。这并不建议 Set 比较的可定制性,但如果您使用新的 Record 或 Tuple 而不是 Object 或 Array,它会直接支持深度对象比较,从而解决这里的原始问题。
请注意,该提案于 2021 年中期进入第二阶段。最近一直在推进,但肯定还没有完成。
可以追踪 Mozilla 在这项新提案上的工作here https://bugzilla.mozilla.org/show_bug.cgi?id=1658309.
原答案
The ES6 Set
对象没有任何比较方法或自定义比较扩展性。
The .has()
, .add()
and .delete()
方法仅在与原语相同的实际对象或相同的值时起作用,并且没有办法插入或替换该逻辑。
你大概可以从一个派生你自己的对象Set
并替换.has()
, .add()
and .delete()
方法首先进行深度对象比较以查找该项目是否已在集合中,但性能可能不会很好,因为底层Set
对象根本没有帮助。在调用原始对象之前,您可能必须对所有现有对象进行强力迭代,以使用您自己的自定义比较来查找匹配项.add()
.
这里有一些信息来自这篇文章和讨论 http://www.2ality.com/2015/01/es6-maps-sets.htmlES6 特性:
5.2 为什么我无法配置映射和集合如何比较键和值?
问题:如果有一种方法可以配置什么地图就好了
键以及哪些集合元素被认为是相等的。为什么不存在?
答:该功能已被推迟,因为很难
正确有效地实施。一种选择是将回调传递给
指定相等性的集合。
Java 中可用的另一个选项是通过方法指定相等性
该对象实现(Java 中的 equals())。然而,这种方法是
可变对象的问题:一般来说,如果一个对象发生变化,它的
集合中的“位置”也必须改变。但那不是
Java 中会发生什么。 JavaScript 可能会走更安全的路线
仅对特殊的不可变对象启用按值比较
(所谓的值对象)。按值比较意味着两个值
如果它们的内容相等,则认为它们相等。原始值是
在 JavaScript 中按值进行比较。