每個使用JavaScript編程的人都應該對Array很是熟悉。 一般,咱們能夠這樣形容它:數組是表示一種儲存在連續空間中的結構類型(內容能夠爲number,object等)。 例如:[1, 2, 3, 4, 5]
(原文這裏說法存在歧義,具體數組在內存中的存儲方式能夠參考連接一、連接二)javascript
而Set更像是一種抽象的數據類型。它只包含不一樣的元素/對象,不須要連續分配存儲空間。 例如:{1, 2, 3}
java
它們之間最大的差異就是Array中的元素是能夠重複的,而Set中的元素不可重複 。除此以外,Array被認爲是一種索引集合,而Set是一種鍵的集合。es6
索引集合是指按下標做爲索引值排序的數據結構
鍵的集合使用key訪問元素,訪問順序與元素插入順序一致。編程
很簡單對吧?如今可能有人會問,既然這二者如此不一樣,爲何還要將它們進行比較?數組
在編程時,咱們可使用Array或Set來存儲相同的數據集。但根據使用狀況,咱們應該選用正確的數據結構以助於提供最佳的解決方案。爲了實現這個目標,首先咱們須要瞭解它們分別是什麼,有什麼特色和能力。前面的文章中咱們對這兩種數據結構已經有了初步的瞭解,接下來就來看看它們的構建方式。瀏覽器
數組的構建很是簡單直接,在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([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提供的最基本方法進行比較。
console.log(set[0]); //undefined
console.log(arr[0]); //1
複製代碼
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.prototype.push()
方法快速完成——元素將會被插入到數組的末尾。arr.push(4); //[1,2,3,4]
複製代碼
Array.prototype.unshift()
方法實現——元素被插入到數組的頭部。arr.unshift(3); //[3,1,2,3]
arr.unshift(5, 6); //[5,6,3,1,2,3]
複製代碼
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}
複製代碼
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]
複製代碼
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?
delete()
方法,使求兩個Set的交/並集的操做比求兩個數組的交/並集的操做更簡單。總之,就我而言對比Array,Set並無明顯優點,除了在特定場景中,例如當咱們想要以最小成本維護不重複的數據,或者使用到大量不一樣的數據集時只須要使用最基本的集合操做而無需直接訪問元素。
不然,Array一般是更好的選擇。由於在須要時獲取元素更節省CPU工做量。
歡迎討論。
其餘資料連接: