原生 Set 类的方法设计直观,遵循现代 JavaScript 约定。 add() 方法返回集合本身,这使得方法链接成为可能 - 因此可以实现像 mySet.add(1).add(2).add(3) 这样的优雅语法。 has() 方法提供对元素成员资格的闪电般快速的检查,而 delete() 和 clear() 负责集合管理。一个特殊的特性是 size 属性(不是方法),它总是显示当前元素的数量。
特别有趣的是 Set 类提供的各种迭代选项。 values() 方法返回集合值的迭代器,而 entrys() 返回值对 [value, value] - 这种特性是由于与 Map 类的兼容性而产生的。 forEach() 方法可以对元素进行功能处理,类似于数组。这种多样化的迭代选项使得集合的使用尤为灵活。
一个实际的例子说明了原生 Set 类的优雅:在内容管理系统中,我们可以管理文章的标签。代码 article.tags = new Set(['javascript', 'programming', 'web']) 立即创建一个唯一的标签集合。之后,当调用 article.tags.add('javascript') 时,该集合将自动防止重复,而无需我们实施额外的检查。
JavaScript 中集合的性能值得特别考虑,因为选择正确的数据结构会对应用程序的性能产生重大影响。让我们看看不同的操作及其时间复杂度,以了解何时集合是最佳选择以及何时其他数据结构可能更可取。
集合的基本操作——添加、删除和检查元素——都实现了常数时间复杂度 O(1)。这是可能的,因为基于哈希的实现在内部使用对象进行存储。让我们把它想象成一个井然有序的仓库:每件物品都有自己 美国 WhatsApp 数据 的位置,我们可以直接去那里而不必搜索。这种效率与数组形成鲜明对比,在数组中搜索元素需要线性时间复杂度 O(n)。
当确定大小时,集合实现的另一个优点就变得明显了。虽然我们在自己的 MySet 类中维护一个单独的大小计数器,但本机 Set 类使用内部优化,也能保证恒定时间 O(1)。这对于性能关键型应用程序中的频繁大小查询尤其重要。
对集合元素进行迭代自然需要线性时间 O(n),因为每个元素都必须访问一次。这适用于 values() 方法和 forEach()。有趣的是,由于不需要管理索引,因此对于集合而言,此操作通常比对于相同大小的数组更快。一个实际的例子:当我们在 Web 应用程序中处理唯一的用户 ID 时,对集合进行迭代明显比对具有相同 ID 的数组进行迭代要快得多。
数学运算值得特别注意。两个具有 n 和 m 个元素的集合的并集的时间复杂度为 O(n + m),因为我们必须对两个集合进行迭代。对于交集,我们以较小的集合作为基础的优化使我们的复杂度达到 O(min(n,m))。当比较一个非常小的集合与一个非常大的集合时,这种优化尤其明显。