- 作者:老汪软件技巧
- 发表时间:2024-08-25 04:01
- 浏览量:
Set在ES2015规范中被引入到语言中,但它总是看起来不完整。这种情况即将改变。
在ES2015版本的Set中,可用的方法:创建、添加、删除和检查Set的成员关系。如果要操作或比较多个集合,就必须编写自己的函数。值得庆幸的是,TC39(ECMAScript规范建立的委员会)和浏览器厂商一直在为此努力。
在我们看新功能之前,让我们回顾一下JavaScript Set可以做什么?
ES2015 JavaScript集做什么?
让我们来看看ES2015版本的JavaScriptSet可以做些什么。
您可以不带任何参数构造Set,这将创建一个空的Set。或者,使用数组,来初始化Set。
const languages = new Set(["JavaScript", "TypeScript", "HTML", "JavaScript"]);
Set只能包含唯一的值,因此上面的Set有三个成员。可以使用size属性检查这一点。
languages.size;
// => 3
可以使用add函数向Set中添加更多元素。添加一个已经存在Set中的元素不会做任何事情。
languages.add("JavaScript");
languages.add("CSS");
languages.size;
// => 4
可以使用delete从Set中删除元素。
languages.delete("TypeScript");
languages.size;
// => 3
可以使用has函数检查元素是否为Set的成员。Set的一个好处是,这种检查可以在O(1)内完成,而检查元素是否在数组中,则随数组的长度O(n)而变化。
languages.has("JavaScript");
// => true languages.has("TypeScript");
// => false
可以使用forEach或for...of循环遍历Set的元素。元素按照它们加入Set的顺序排序。
languages.forEach(element => console.log(element));
// "JavaScript"
// "HTML"
// "CSS"
最后,可以使用clear函数清空Set。
languages.clear();
languages.size;
// => 0
总结:可以用ES2015规范版本的Set做什么:
但是,这些实现忽略了Set之间的操作。您可能想要创建一个Set,它包含来自其他两个Set的所有项(两个Set的并集),找出两个Set有什么共同点(交集),或者找出在一个集合中不存在而在另一个集合中存在的东西(差集)。
新的Set函数是什么?
新的Set方法添加以下方法实例:union,intersection,difference,symmetricDifference,isSubsetOf,isSupersetOf和isDisjointFrom。
其中一些方法类似于一些SQL连接,我们将使用它们来演示结果和代码。让我们看看每个函数做什么的一些例子。
您可以在Chrome 122或Safari 17中尝试下面的任何代码示例。
Set.prototype.union()
集合的并集是包含任意一个集合中存在的所有元素的集合。
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const backEndLanguages = new Set(["Python", "Java", "JavaScript"]);
const allLanguages = frontEndLanguages.union(backEndLanguages);
// => Set {"JavaScript", "HTML", "CSS", "Python", "Java"}
在本例中,前两个集合中的所有语言都在第三个集合中。
这相当于两个表之间的SQLFULL OUTER JOIN。
Set.prototype.intersection()
交集是包含两个集合中存在的所有元素的集合。
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const backEndLanguages = new Set(["Python", "Java", "JavaScript"]);
const frontAndBackEnd = frontEndLanguages.intersection(backEndLanguages);
// => Set {"JavaScript"}
“JavaScript”是这里两个集合中出现的共同元素。
交集就像一个INNER JOIN。
Set.prototype.difference()
正在处理的集合和另一个集合之间的区别是所有元素在第一个集合中出现,而在第二个集合中没有出现。
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const backEndLanguages = new Set(["Python", "Java", "JavaScript"]);
const onlyFrontEnd = frontEndLanguages.difference(backEndLanguages);
// => Set {"HTML", "CSS"}
const onlyBackEnd = backEndLanguages.difference(frontEndLanguages);
// => Set {"Python", "Java"}
在寻找集合之间的差异时,你在哪个集合上调用函数以及哪个集合是参数是很重要的。在上面的例子中,从前端语言中删除后端语言会导致“JavaScript”被删除,并在结果集中返回“HTML”和“CSS”。然而,从后端语言中删除前端语言仍然会导致“JavaScript”被删除,并返回“Python”和“Java”。
差异就像执行LEFT JOIN操作。
Set.prototype.symmetricDifference()
两个集合之间的对称差是一个包含其中一个集合中的所有元素,但不包含两个集合中的所有元素的集合。
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const backEndLanguages = new Set(["Python", "Java", "JavaScript"]);
const onlyFrontEnd = frontEndLanguages.symmetricDifference(backEndLanguages);
// => Set {"HTML", "CSS", "Python", "Java"}
const onlyBackEnd = backEndLanguages.symmetricDifference(frontEndLanguages);
// => Set {"Python", "Java", "HTML", "CSS"}
在这种情况下,结果集中的元素是相同的,但请注意顺序不同。集合顺序由元素添加到集合的顺序决定,在其上执行函数的集合将首先添加其元素。
对称差异类似于排除两个表中的相同元素的FULL OUTER JOIN。
Set.prototype.isSubsetOf()
如果第一个集合中的所有元素都出现在第二个集合中,则该集合是另一个集合的子集。
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const declarativeLanguages = new Set(["HTML", "CSS"]);
declarativeLanguages.isSubsetOf(frontEndLanguages);
// => true
frontEndLanguages.isSubsetOf(declarativeLanguages);
// => false
集合也是它自身的子集。
frontEndLanguages.isSubsetOf(frontEndLanguages);
// => true
Set.prototype.isSupersetOf()
如果第二个集合中的所有元素都出现在第一个集合中,则该集合是另一个集合的超集。它与子集的关系是相反的。
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const declarativeLanguages = new Set(["HTML", "CSS"]);
declarativeLanguages.isSupersetOf(frontEndLanguages);
// => false
frontEndLanguages.isSupersetOf(declarativeLanguages);
// => true
集合也是自身的超集。
frontEndLanguages.isSupersetOf(frontEndLanguages);
// => true
Set.prototype.isDisjointFrom()
最后,如果一个集合与另一个集合没有共同的元素,则它们是不相交的。
const frontEndLanguages = new Set(["JavaScript", "HTML", "CSS"]);
const interpretedLanguages = new Set(["JavaScript", "Ruby", "Python"]);
const compiledLanguages = new Set(["Java", "C++", "TypeScript"]);
interpretedLanguages.isDisjointFrom(compiledLanguages);
// => true
frontEndLanguages.isDisjointFrom(interpretedLanguages);
// => false
这些集合中的解释语言和编译语言不重叠,因此集合是不相交的。前端语言和解释语言确实与元素“JavaScript”重叠,因此它们并不是分离的。
支持
在撰写本文时,该提案处于TC39进程的第三阶段,Safari 17(2023年9月发布)和Chrome 122(2024年2月)已经发布了这些方法的实现。Edge紧随Chrome, Firefox Nightly也有支持,我预计这两款浏览器也会很快发布支持。
Bun使用了Safari的JavaScriptCore引擎,因此已经支持了这些新功能。Chrome的支持意味着它已经被添加到V8 JavaScript引擎中,并将很快被Node.js采用。
希望该提案将进入流程的第4阶段,甚至可能在最终确定之前及时加入ES2024规范。
Polyfills
虽然您需要旧的JavaScript引擎支持,可以使用polyfill将这些函数升级到符合规范的实现。它们可以在core-js中使用,也可以作为es-shims项目中每个函数的单独包使用(例如,set.prototype.union包可用于union功能)。
如果您已经为这些函数中的任何一个编写了自己的实现,我建议首先升级到polyfills,然后随着支持变得更加广泛而逐步淘汰它们。
原文: