Javascript 关于ES6'的使用,我如何检查类实例的相等性和相同性;什么是集合?
我正在尝试通过使用TypeScript使用ES6。我需要了解如何为在应用程序中使用的对象创建。例如,对象如下所示Javascript 关于ES6'的使用,我如何检查类实例的相等性和相同性;什么是集合?,javascript,typescript,ecmascript-6,set,typescript-typings,Javascript,Typescript,Ecmascript 6,Set,Typescript Typings,我正在尝试通过使用TypeScript使用ES6。我需要了解如何为在应用程序中使用的对象创建。例如,对象如下所示 class Product { metadata: Map<String, String> constructor(id: number) { metadata = new Map<String, String>(); } public addMetadata(key: String, val: String): Product { th
class Product {
metadata: Map<String, String>
constructor(id: number) {
metadata = new Map<String, String>();
}
public addMetadata(key: String, val: String): Product {
this.metadata.set(key, val);
return this;
}
}
Set
或Map
仅当某个键是完全相同的对象,而不是具有相同内容的不同对象,而是相同的实际对象时,才会认为该键是相同的对象。换句话说,它的工作原理与obj1===obj2
类似
如果你使用的是一个集合
,比如你的标题和第一段所指的,那么你就很不走运了。两个具有相同内容的独立对象(或在您的情况下,相同的.id
属性)将被视为集中的独立项,因为它们实际上是不同的对象
在这个问题中,您可以看到一个讨论,它是关于集合是否可自定义的
如果您使用的是映射
(这似乎是您的代码所引用的,尽管问题的文本中没有这样说),那么您可以使用.id
属性作为键,对象本身作为值。只要.id
属性是一个基元(如字符串或数字),那么对于任何给定的id
您将只能在映射中获得一个项,而不是直接回答您的问题,但是“标记集”(因为缺少更好的名称)可能比重写的相等运算符工作得更好。这样,“相等”是集合本身的属性,而不是底层对象的属性。下面是一个JS示例:
类SetBy扩展集{
建造师(pred){
超级();
this.pred=pred;
this.inner=新集合();
}
has(obj){
返回this.inner.has(this.pred(obj));
}
添加(obj){
如果(!this.has(obj)){
this.inner.add(this.pred(obj));
super.add(obj);
}
}
}
s=新的立根(x=>x.id);
a={id:1,名称:'a'};
b={id:1,名称:'b'};
c={id:1,名称:'c'};
d={id:2,名称:'d'};
e={id:2,名称:'e'};
s、 添加(a);
s、 添加(b);
s、 添加(c);
s、 加(d);
s、 加(e);
console.log([…s])代码>检查对象是否相等的简单(也是有效)方法是比较JSON.stringify()
字符串。由于只有自己的可枚举属性是字符串化的,元数据
属性应该是不可枚举的:
class Product {
metadata: Map<String, String>
constructor(public id: number) {
Object.defineProperty(this, 'metadata', {
configurable: true,
writable: true
})
this.metadata = new Map<String, String>();
}
...
}
此方法可用于自定义集合
:
class ObjectedSet extends Set {
protected _find(searchedValue) {
for (const value of Array.from(this.values()))
if (JSON.stringify(value) === JSON.stringify(searchedValue))
return searchedValue;
}
has(value) {
return !!this._find(value);
}
add(value) {
if (!this.has(value))
super.add(value);
return this;
}
delete(value) {
const foundValue = this._find(value);
if (foundValue)
super.delete(foundValue);
return !!foundValue;
}
}
我没有一个好的答案,但可以澄清一些事情。在javascript中,非原语的“==”或“==”表示引用相等。因此,它必须是完全相同的实例才能计算为“true”(根本不检查属性)。我还没有对“Set”和“Map”做过太多的研究,但希望这能有所帮助。@Aliester可能是重复的——作为回答另一个问题的人,我并不认为这是重复的。这里的问题完全不同。阅读其他答案可能会给你一些信息,你可以用这些信息来回答这个问题,但是没有人会说这个问题和那个问题是一样的。@如果我误解了,jfriend00表示歉意,但OP本质上不是在问如何使用自定义javascript对象和集合,并提供他自己的自定义相等性计算,而不是本机逻辑吗?不过,我会听从你的意见。@Aliester-首先,OP对他们使用的是Set
还是Map
有点困惑。问题的文本指的是集合
,但代码指的是地图
。如果他们正在使用映射
,并且可以将id
值作为映射
中的键,那么他们的问题可能会得到解决。让我们先看看结果如何。这种方法忽略了delete
。实现它不如添加它有趣。add
@estus:它也可能是一行,否?@georg否,因为您需要从外部集合中删除与被删除对象具有相同谓词的对象。指向外部对象的内部映射
(而不是集
)可能会解决这个问题。@Bergi:有道理。OP实际上在寻找的似乎是映射未设置。字符串序列化听起来像是一种进行等式比较的非常不高效的方法。为什么你认为它很快?“BurgI我会想到的,但是在我自己的基准中,代码> JSON。StrugInt[/COD] >与<代码>的比较。这两种方法都很快,所以这种考虑属于初步优化范畴。如果Lodash不在项目中使用,我会考虑<代码> JSON。StrugIng/<代码>一个无脑的。是的,对于小而相等的输入,我会把它们放在同一个水平上。但是,如果两个输入共享一个大的数据结构(即.isEqual
可以通过引用标识进行检查),或者是一个大的但不相等的数据结构(即JSON.stringify
仍然需要完全遍历),我预计会有很大的差异。@Bergi当然。IIRC,stringify在同等对象上的表现略优于isEqual,在不平等对象上的表现略逊于isEqual。在我的用例中,我有一般的小对象(总共10-20个可枚举的道具),性能根本不是问题。
new Product(1) !== new Product(1);
JSON.stringify(new Product(1)) === JSON.stringify(new Product(1));
JSON.stringify(new Product(1)) !== JSON.stringify(new Product(2));
class ObjectedSet extends Set {
protected _find(searchedValue) {
for (const value of Array.from(this.values()))
if (JSON.stringify(value) === JSON.stringify(searchedValue))
return searchedValue;
}
has(value) {
return !!this._find(value);
}
add(value) {
if (!this.has(value))
super.add(value);
return this;
}
delete(value) {
const foundValue = this._find(value);
if (foundValue)
super.delete(foundValue);
return !!foundValue;
}
}