【问题标题】:Why does ECMAScript 6 include Set objects, but doesn't provide a way to compare them for equality?为什么 ECMAScript 6 包含 Set 对象,但没有提供比较它们是否相等的方法?
【发布时间】:2016-02-01 17:42:18
【问题描述】:

我可以在 ES6 中创建集合:

let s = new Set([1, 2, 3]);
let q = new Set([3, 1, 2]);

但无法通过它们包含的内容来比较它们。

console.log(s == q); // --> false

API 中没有提供.equals(other) 方法,只有.has()delete() 等。天真地,在我看来,它似乎很容易实现——为什么不呢?

(我不是在寻找解决方法,就像在this 答案中提供的那样。我只是想知道为什么会做出这个决定,因为围绕它的情况肯定有一些我不明白的地方。)

【问题讨论】:

  • 不太清楚,但您可以将任何东西添加到集合中,包括对象。所以猜他们不想处理这个
  • @juvian:但他们已经用.has() 做到了这一点,不是吗?这通过引用相等来起作用。
  • 必须返回并审查标准委员会的审议。或许是考虑过的。然而,我想它不是。正如@JimboJonny 指出的那样,其他对象类型没有这样的相等API。语言设计者在添加功能时非常保守,尤其是那些可以在用户空间轻松实现的功能。

标签: javascript ecmascript-6


【解决方案1】:

这并不新鲜。

非原始对象(即对象)的等价性比较它们在字面上是否是相同的实际对象。这不是一个新概念。对 JS 中的其他非原始内容同样适用:

var a = [1,2,3];
var b = [1,2,3];
console.log(a == b); // -> false

var c = {foo:'bar'};
var d = {foo:'bar'};
console.log(c == d); // -> false

为什么基元/对象比较不同?

简单:因为 2 个图元是否“相同”的概念与 2 个对象是否“相同”的概念不同。

您实际上可以对同一个对象进行多次引用,因此检查两个引用是否“相同”具有与原语非常不同的含义。它们实际上可能是指向同一个对象的实际指针:

var str1 = 'foo';
var str2 = str1;
str2 += ' bar';
console.log(str2); // -> "foo bar"
console.log(str1); // -> still just "foo"
// str1 is unchanged, primitives don't do pointers

var obj1 = {val:'foo'};
var obj2 = obj1;
obj2.val += ' bar';
console.log(obj2.val); // -> "foo bar"
console.log(obj1.val); // -> "foo bar"
// obj1 and obj2 are LITERALLY pointers to the same thing
// changing one changes the other

因此,对于原语(它们存在的一个完整点是值足够原始,即使它们实际上并未在内部指向相同的实际 1 和 0,我们也可以比较它们)可能与当我们问“它们是否等价”时,非基元(其中 2 个值可能在内部从字面上指向相同的 1 和 0)?


更不用说技术上的困难了。

基元之所以这样称呼是有原因的:它们是简单/原始的值。因此,它们很容易比较。

对象在设计上要复杂得多。他们甚至可以持有对其他对象的引用……甚至是对自己的引用。以您暗示的方式比较它们应该是一个可能无限的迭代过程,而不是简单的操作员操作。考虑一下:

var a = {foo:'bar'};
a.a = a;
console.log(a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.foo); // -> bar
// could go on forever that way

制作诸如检查等效性之类的东西突然意味着可能无限的迭代过程将对语言产生深远的负面影响。更有意义的是,它们只是检查它们是否字面上相等(即指向同一个确切的对象)。

【讨论】:

  • 您好,感谢您的回答!我想,在我的脑海中,我正在将 JS 与 Python 进行比较,Python 提供了一个由a == b 调用的__eq__。在 Python 中,检查等效性是一个可能无限的迭代过程,正如您所说,当 a 包含对自身的引用时。因此,我不认为“检查它们是否字面上相等更有意义”是不言而喻的。您认为造成语言差异的原因是什么?
  • @EliRose - 你必须解释得更好,因为我对 python 的经验是它在这方面的工作原理完全相同。例如。此代码:pastie.org/10704573 将输出 false 然后 true 就像等效的 JS 代码一样。诚然,我不是 Python 专家,但我知道的足够多,可以比较 vars 并打印输出,而且当我这样做时,它似乎在这方面表现得就像 JS。
  • 虽然所有这些都是好东西,并且可能是并且可能是不支持这种相等检查的部分原因,但底线是它是对语言设计者思维过程的推测。
  • @JimboJonny:是的,Python 在这方面的工作原理是一样的,except 如果你在类上定义了特殊的__eq__ 方法。这是一个示例:repl.it/Bije/0。这允许例如[1, 2, 3] == [1, 2, 3] 在 Python 中为真,但在 Javascript 中为假。 Java 对equals() 做同样的事情。所以我有一个问题是什么设计决定导致 JS 不提供__eq__ 钩子。
  • @EliRose - 这只是运算符重载,您在其中定义要在== 上运行的算法。您可以将其定义为在比较时返回"purple"。这并不意味着问为什么 JS 中的 == 不会评估为 "purple" 是合乎逻辑的。并且在您的重载通知中,您必须降低到预期的原始值才能使您的比较按预期工作。在您期望重载代码中的原语的地方引入另一个非原始值而无需自定义重载,但它再次失败:repl.it/Bije/1
猜你喜欢
  • 1970-01-01
  • 2013-08-18
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多