如果我有一组对象,例如
const s = new Set();
s.add({a: 1, b: 2});
s.add({a: 2, b: 2});
我会做
s.has({a: 1, b: 2});
我会得到正面的结果吗? Set
如何处理引用类型?有没有办法告诉它使用自定义检查器/谓词?
答案 0 :(得分:3)
根据docs:
Set对象使您可以存储任何类型的唯一值,无论是否 基本值或对象引用。
在添加对象时,它们的引用将存储在内部,并且由于将不同的对象传递给false
方法,因此检查将返回has
。
实际上,您的案件甚至涵盖在Examples section of the has method reference中。
答案 1 :(得分:2)
关于对象,Set处理唯一的引用。
new Set([ {a: 1}, {a: 1} ])
有两项。
var x = {a: 1}; new Set([ x, x ]);
有一项。
没有办法让Set使用自定义比较功能。
答案 2 :(得分:1)
期望任何本机JavaScript API均通过引用而不是内容(包括浅表比较)来比较对象:
({a: 1, b: 2}) !== ({a: 1, b: 2})
Set
不是排除项,它是does ===
comparison for every value but NaN
,当它使用has
查找值或存储唯一值时。
这可以通过扩展Set
并在has
等方法中使用深度比较来实现,但效率不高。
一种更有效的方法是使用Map
,因为应该使用规范化的键来存储和检索条目,但是应该存储实际的对象。可以使用JSON.stringify
来完成,但是对象键也应该优先排序,因此可以使用第三方实现,例如json-stable-stringify
。
在这一点上,扩展Set
或Map
可能不会带来太多好处,因为应该重写大多数方法:
class DeepSet {
constructor (iterable = []) {
this._map = new Map();
for (const v of iterable) {
this.add(v);
}
}
_getNormalizedKey(v) {
// TODO: sort keys
return (v && typeof v === 'object') ? JSON.stringify(v) : v;
}
add(v) {
this._map.set(this._getNormalizedKey(v), v);
return this;
}
has(v) {
return this._map.has(this._getNormalizedKey(v));
}
// etc
}
请注意,此集合仅适用于可以正确序列化为JSON的普通对象。可能还有其他方法可以序列化对象内容,但是没有一种方法可以正确处理所有可能的值,例如符号和类实例。
答案 3 :(得分:1)
您无法比较引用(例如数组和对象)是否相等。您可以比较值!!!
const s = new Set();
let a = {a: 1, b:2};
let b = {a: 2, b: 3};
s.add(a);
s.add(b);
s.has(a); //true