【译】Array与Set的异同及使用场景

Set vs Array
原文连接: 戳这里
PS:原文只介绍了Array和Set的一些简单操做,详细API放在文章底部。

Array和Set是什么

每个使用JavaScript编程的人都应该对Array很是熟悉。 一般,咱们能够这样形容它:数组是表示一种储存在连续空间中的结构类型(内容能够为number,object等)。 例如:[1, 2, 3, 4, 5]
(原文这里说法存在歧义,具体数组在内存中的存储方式能够参考连接一连接二javascript

而Set更像是一种抽象的数据类型。它只包含不一样的元素/对象,不须要连续分配存储空间。 例如:{1, 2, 3}java

它们之间最大的差异就是Array中的元素是能够重复的,而Set中的元素不可重复 。除此以外,Array被认为是一种索引集合,而Set是一种键的集合。es6

索引集合是指按下标做为索引值排序的数据结构
键的集合使用key访问元素,访问顺序与元素插入顺序一致。编程

很简单对吧?如今可能有人会问,既然这二者如此不一样,为何还要将它们进行比较?数组

在编程时,咱们可使用Array或Set来存储相同的数据集。但根据使用状况,咱们应该选用正确的数据结构以助于提供最佳的解决方案。为了实现这个目标,首先咱们须要了解它们分别是什么,有什么特色和能力。前面的文章中咱们对这两种数据结构已经有了初步的了解,接下来就来看看它们的构建方式。浏览器

如何构建

Array

数组的构建很是简单直接,在JS中声明一个数组你能够直接使用字面上的语法:数据结构

var arr = []; //空数组
var arr = [1,2,3]; //元素为1,2,3的数组
复制代码

或者使用构造函数:函数

var arr = new Array(); //空数组
var arr = new Array(1,2,3);//元素为1,2,3的数组
复制代码

甚至这种更酷的方法:性能

var arr = Array.from("123"); //["1","2","3"]
复制代码

注: 一条建议——除了非用不可的状况尽可能不要使用new Array(),缘由以下:ui

  • new Array()的性能比[]慢不少
  • []节约更多输入的时间
  • 你可能会犯一些经典的错误,好比:
var arr1 = new Array(10); //长度为10,每一个元素都为undefined
var arr2 = [10]; // arr2[0] = 10 且 arr2.length = 1;
var arr3 = new Array(1,2,3); //[1,2,3]
var arr4 = [1,2,3];//[1,2,3] 
复制代码

因此,尽可能保持一个原则——简单化

Set

Set使用内置的构造函数初始化,没有其它简便的方法。

Set([iterable])

想要建立一个Set,须要使用new方法,例如:

var emptySet = new Set(); 
var exampleSet = new Set([1,2,3]);
复制代码

不能使用以下方式:

new Set(1);
复制代码

Set接收一个可遍历的对象做为其输入参数,并将遍历元素依次做为Set中的元素生成对象。所以,咱们能够经过数组做为参数去建立Set——但建立的Set中只包含数组中的非重复元素,如上文提到,Set中元素不可重复。

固然,咱们也能经过Array.from()方法将Set还原为数组:

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

如今,咱们知道了如何构建这两种数据结构,接下来让咱们对Array / Set提供的最基本方法进行比较。

访问元素

  • 首先Set不支持像Array同样经过索引随机访问元素
console.log(set[0]); //undefined
console.log(arr[0]); //1
复制代码
  • 更重要的是,由于Array中的数据存储在连续的空间中,因此CPU可以经过预处理操做更快地进行数据访问。所以,与其余类型的抽象数据类型进行比较,访问Array中的元素(按顺序,例如for循环)一般会更快更有效。
  • 判断一个元素是否在Set中的语法比判断是否在Array中更简洁。Set:Set.prototype.has(value)。Array:Array.prototype.indexOf(value)
console.log(set.has(0)); // boolean - false
console.log(arr.indexOf(0)); // -1
console.log(set.has(1)); //true
console.log(arr.indexOf(1)); //0
复制代码

这意味着在Array中,咱们须要额外建立检查元素是否在Array中的条件:

var isExist = arr.indexOf(1) !== -1;
复制代码

:ES6提供了与Set.prototype.has()类似的方法Array.prototype.includes()来判断元素是否在数组中,但这个方法并无普遍地被浏览器支持——好比IE..

插入元素

Array

  • 向数组中插入元素可使用时间复杂度为O(1)的Array.prototype.push()方法快速完成——元素将会被插入到数组的末尾。
arr.push(4); //[1,2,3,4]
复制代码
  • 或者可使用时间复杂度为O(n)的Array.prototype.unshift()方法实现——元素被插入到数组的头部。
arr.unshift(3); //[3,1,2,3]
arr.unshift(5, 6); //[5,6,3,1,2,3]
复制代码

Set

  • 只有一个方法能够在Set中插入元素——Set.prototype.add()。因为Set须要保持其“元素不可重复”的特性,因此每次调用add()方法,Set都须要便利全部元素以确保无重复元素,一般状况下add()方法的时间复杂度应为O(n)。不过Set的内部采用哈希表的实现方式,所以能够达到O(1)的时间复杂度。
set.add(3); //{1,2,3} 
set.add(4); //{1,2,3,4}
复制代码

删除元素

Array

  • 使数组如此受欢迎的缘由之一是它提供了许多不一样的方法去删除元素,例如:
var arr = [5, 6, 1, 2, 3, 4]
复制代码

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, delectCount)——删除从index开始的delectCount个元素。时间复杂度为O(n)

arr.splice(0,1); //[1,2,3]
复制代码

Set

var set = new Set([1, 2, 3, 4]);
复制代码

delete(element)——删除指定的element

set.delete(4); //{1,2,3}
复制代码

clear()——清空Set中全部元素

set.clear(); //{}
复制代码

Array并未提供原生方法删除指定元素,咱们须要借助其它方法找到元素对应下标,经过splice()删除,而Set能够直接使用delete()进行删除。

另外,对比Set只提供了一些基本的操做数据的方法,Array提供了更多实用的原生方法(reduce(),map(),sort()等),因此有些人可能会想,为何咱们比起Array会更喜欢Set?

Array和Set的应用场景

  • 首先,Set与Array是不一样的两种数据结构,它并非要彻底替换Array,而是提供额外的数据类型来完成Array缺乏的一些功能。
  • 因为Set只包含不一样的元素,若是咱们只但愿存储不一样的元素,使用Set会更好。
  • 能够利用Set的一些原生方法轻松的完成数组去重,查找数组公共元素及不一样元素等操做。Set的delete()方法,使求两个Set的交/并集的操做比求两个数组的交/并集的操做更简单。
  • 数组适用于但愿保留重复元素,可能进行大量修改(增、删操做),或是但愿经过索引对元素进行快速访问的场景。(试想对一个Set进行二分查找——如何获取到Set的中间元素?)

结论

总之,就我而言对比Array,Set并无明显优点,除了在特定场景中,例如当咱们想要以最小成本维护不重复的数据,或者使用到大量不一样的数据集时只须要使用最基本的集合操做而无需直接访问元素。

不然,Array一般是更好的选择。由于在须要时获取元素更节省CPU工做量。

欢迎讨论。

其余资料连接:

相关文章
相关标签/搜索