本日将重点比拟两个数据构造,即 Array 和 Set,话不多说,直接开始。

1.什么是 Set 和 Array?

到目前为止,每个利用 JS 的人都熟习 Array,但数组到底是什么?一样平常来说,数组是一种构造,表示在连续内存等分配的数据块(数字、工具等)。
比如:

[1, 2, 3, 2];

那 Set 又是什么?Set(凑集) 作为数学观点更为人熟知,它是一种抽象数据类型,它只包含不同的元素/工具,不须要按索引顺序分配。
比如:

php根据array创建set什么时刻用Array什么时刻用Set Bootstrap

{ 1, 2, 3;}

以是从观点上看,Array 和 Set 在技能上是不同的观点。
您可能会把稳到,这里最大的差异之一是 Array 中的元素可以重复(除非您见告它不要重复),而在 Set 中,它们不能重复(无论您如何决定)。

此外,Array 被认为是“索引凑集(indexed collection)”类型的数据构造,而 Set 被认为是“键控凑集(keyed collection)”。

索引凑集:是按索引值排序的数据凑集键控凑集:是利用键的凑集,其包含可按插入顺序迭代的元素

在编程天下中,存储相同的数据集(无重复)可以利用 Array 或 Set 作为构造来存储。
然而,选择精确的构造有助于供应最佳办理方案,这也是我们希望实现的目标。

2.如何布局 Set 和 Array?2.1 布局 Array

数组非常大略,要在 JS 中声明新数组,可以采取如下办法:

var arr = []; //Empty arrayvar arr = [1, 2, 3]; //Array which contains 1,2,3

或者利用内置布局函数:

var arr = new Array(); //empty arrayvar arr = new Array(1, 2, 3); //Array which contains 1,2,3

或者利用 Array.from 方法:

var arr = Array.from('123'); //["1","2","3"]

把稳:除非你真的须要,否则不要利用 new Array(),由于:

它比普通的 [] 符号实行的慢得多[] 节省更多的打字韶光您可能终极会犯一些意想不到的缺点,例如:

var arr1 = new Array(10);//arr1[0] = undefined but arr1.length = 10var arr2 = [10];// arr2[0] = 10 and arr2.length = 1;var arr3 = new Array(1, 2, 3);//[1,2,3]var arr4 = [1, 2, 3];//[1,2,3]2.2 布局 Set

只能通过 Set 内置的布局函数来创建 Set。

var emptySet = new Set();var exampleSet = new Set([1, 2, 3]);

但是绝对不要这样:

new Set(1);

Set 吸收可迭代工具作为其输入参数,并将分别创建 set 工具。
因此,可以从一个数组布局一个凑集,但是它只会包含来自该数组的不同元素,也便是没有重复元素。
当然,也可以利用 Array.from() 方法将凑集转换回数组。

var set = new Set([1, 2, 3]);// {1,2,3}var arr = Array.from(set);//[1,2,3]

好的,既然知道如何创建它们,那么它们的功能呢?让我们对 Array/Set 供应的最基本的方法做一个小的比较。

2.2.1 定位/访问一个元素首先,Set 不支持像 Array 那样通过索引随机访问元素,这意味着:

console.log(set[0]);//undefinedconsole.log(arr[0]);//1由于 Array 数据存储在连续的内存中,CPU 能够通过预取而更快地访问数据。
因此,与其他类型的抽象数据类型比较,常日访问数组中的元素(例如在 for 循环中)会更快、更高效。
利用 Set.prototype.has(value) VS Array.prototype.indexOf(value) 检讨元素是否在 Set 中的语法比 Array 更大略

console.log(set.has(0)); // boolean - falseconsole.log(arr.indexOf(0)); // -1console.log(set.has(1)); //trueconsole.log(arr.indexOf(1)); //0

把稳:ES6 确实供应了 Array.prototype.includes() ,它的行为类似于 has(),但是,它没有得到广泛支持,比如 IE 浏览器便是特例。

2.2.2 插入元素

通过利用 Array.prototype.push() 可以在韶光繁芜度为 O(1)的情形下快速完成向 Array 添加新元素,此时元素将被添加到数组的末端。

arr.push(4); //[1,2,3,4]

或者也可以利用 Array.prototype.unshift() 在韶光繁芜度为 O(n)的情形下完成将元素添加到数组的开头,此时 n 是当前数组的长度。

arr.unshift(3); //[3,1,2,3]arr.unshift(5, 6); //[5,6,3,1,2,3]在 Set 中,只有一种方法可以添加新元素,即 Set.prototype.add()。
由于 Set 必须掩护其凑集成员之间的“不同”属性,因此在每次调用 add() 时,Set 都须要检讨所有成员以确保没有重复。
常日 add() 将花费 O(n) 的运行韶光。
然而,由于哈希表实现方法,Set 中的 add() 可能只须要 O(1)。

set.add(3); //{1,2,3}set.add(4); //{1,2,3,4}

因此 Set 在添加元素方面险些和 Array 韶光繁芜度同等。

2.2.3 移除元素

Array 如此盛行的好处之一是由于它供应了许多不同的方法来删除元素,例如:

Pop() : 删除并返回末了一个元素,韶光繁芜度 O(1)

arr.pop(); //return 4, [5,6,1,2,3]Shift() — 删除并返回第一个元素,韶光繁芜度 O(n)

arr.shift(); //return 5; [6,1,2,3]Splice(index, deleteCount): 从索引开始删除 deleteCount 个元素,韶光繁芜度最多为 O(n)。

arr.splice(0, 1); //[1,2,3]

在 Set 中可以利用如下方法来移除元素。

Delete(element) — 从 Set 中删除特定的给定元素

set.delete(4); //{1,2,3}Clear() — 从 Set 中删除所有元素

set.clear(); //{}

虽然 Array 不支持本地构建的方法来删除特定的元素(除非知道它的索引),但须要一个额外的外部函数的帮助来查找该元素的索引并实行 splice(),而 Set 会更加大略。

此外,与目前仅具有上述最基本功能的 Set 比较,Array 确实供应了更多的原生功能(reduce()、reverse()、sort() 等)。

3.什么时候利用 Array?什么时候 Set?首先,Set 不同于 Array。
它并不是要完备取代 Array,而是供应额外的支持类型来完成 Array 缺失落的部分。
由于 Set 只包含不同的元素,如果事先知道数据不会重复,利用 Set 会更加省心Set 的基本操作,如 union()、intersect()、difference() 等可以根据本机内置(built-in)操作轻松有效地实现。
由于 delete() 方法存在,使得两个 Set 的交并操作比数组随意马虎的多Array 适用于保持元素有序以便快速访问,或进行大量修正(删除和添加元素)或任何必要对元素进行直接索引访问的操作(例如,考试测验对 Set 而不是 Array 做二分查找,如何获取中间元素)

总的来说,Set 与 Array 比较并没有明显的上风,除非在特定情形下。
例如当想要以最小本钱掩护数据的唯一性,或者同时处理大量不同的数据集时利用最基本的凑集操作,无需直接访问元素。
否则,Array 该当始终是首选。
下一篇文章将重点先容通过Set来提升程序性能的方案,欢迎大家持续关注~

参考资料

原文作者:Maya Shavin

原文链接:https://medium.com/front-end-weekly/es6-set-vs-array-what-and-when-efc055655e1a