0%

陣列 Array 有哪幾種型態 ?

Day 06

JavaScript 一定是個女人,有個性、特立獨行、難以理解,還可以ㄧ次做很多事。

有時候思索著,在學習程式的時候,到底是不是應該把我們所知道的知識,更有系統的整理出來?但是當我們在整理我們所學的知識時,要如何知道我們所整理的資料正確性? 有時有理解障礙 尤其程式這東西,在學習時常感到很抽象,很多時候讀了幾遍書上寫的,照著範例實做了,卻還是無法理解真正的含義,這或許和學外語很相似,學習一個新的外國語言,會聽、會寫、會講都會有好幾個階段,也需要時間去消化與沈澱,持續的學習與練習是必要的,直到有一天,當我們突然發現自己聽得懂外國人在說什麼,那種喜悅應該是很難形容的吧?

小小感想,只因今天是週六?鐵人賽已經來到了第六天,我的陣列小菜今天比較清淡喔~來聊聊陣列有幾種。

要分哪幾種?一定要分嗎?好吧。第一種:空陣列 arr = [] 不要打我 ,如果這個也要算,那是不是只有數字為元素的也要算一種?不同型別的也要算一種?不行,這樣也太膚淺了,感覺很沒誠意。

如果真要分,本人認為 本人而已喔 應該只能算三種:

  • 密集陣列 (dense)
  • 稀疏陣列 (sparse)
  • 類陣列 (array-like)

密集陣列 (dense) 坐滿做好

陣列裡的元素沒有空值,也沒有 undefined,一般在宣告或創建陣列時沒有空隙。像這樣:
https://ithelp.ithome.com.tw/upload/images/20190921/20104175Rio5A1NMVE.jpg

稀疏陣列 (sparse) 稀稀落落

一般的陣列裡的元素是連續的索引值,元素之間有缺口(gaps),是稀疏陣列。
我們可以從.length 得知陣列的長度。但是如果是稀疏陣列,length 屬性的值也會大於陣列內元素的數目。
如果在指定或創建陣列時,省略某個值不寫、逗號間沒有值,產生的陣列就會是稀疏陣列,值被省略的陣列元素並不存在,這些缺口會顯示 undefined

1
2
3
4
5
let arrSparse = ['a', 'b', , 'e', , 'g']; // 元素之間有缺口
var arr1 = [,]; // [empty] a1 沒有元素,a1.length 卻是1
var arr2 = [undefined]; // a2 陣列有一個元素為 undefined ,a2.length 也是1
0 in arr1; // -> false a1 沒有索引值0 所以回傳 false
0 in arr2; // -> true a2 在索引值0的位置有undefined 所以回傳 true

理解稀疏陣列是理解 Javascript 陣列真實本質的重要步驟,雖然實務上會遇到稀疏陣列的機會很少,但是如果真的遇到了,也會把它們視為有undefined元素的非稀疏陣列來操作。

https://ithelp.ithome.com.tw/upload/images/20190921/20104175Tr0q5xcqR0.jpg

類陣列 (array-like) 半牛半馬

當初在「大全」裡看到這句時,實在摸不著頭緒,「不是所有的陣列都可以用陣列的方法」 是歧視嗎? 大全上這樣寫著。更貼切的來說,是類陣列不能直接使用 JavaScript 內建 Array 的方法,在大全裡介紹類陣列的標題寫著「類陣列物件」,又是陣列又是物件的,實在是很讓人混淆,到底是陣列還是物件?JavaScript 也有這麼曖昧的東西啊?

typeof 來查看陣列,會得到物件 object,但到底陣列和其他物件有什麼不同?最大的不同是陣列有:

  • length這個特殊屬性
  • Array.prototype繼承過來的許多實用的方法
  • 陣列的class屬性值為Array這幾點吧。

但是所謂的「類陣列」(Array-like) 也是如此嗎?並不是喔。

先來看看類陣列長什麼樣子:

1
2
3
4
5
6
7
8
9
10
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
push: Array.prototype.push,
splice: Array.prototype.splice
};
obj.push('d');
obj; // {0: "a", 1: "b", 2: "c", 3: "d", length: 4, push: ƒ}

https://ithelp.ithome.com.tw/upload/images/20190921/201041752EQ2YNsI0a.png

講直白一點,類陣列是物件,可以當成陣列來用 或是是陣列,可以當成物件用
我們可以看到obj的元素是用花括號 {},是物件的做法。但是物件裡又有length: 3這個陣列的屬性。這就對了,任合物件只要具有數值length屬性,且數值不是負整數,就可以說是類陣列(Array-like)。

函數引數所形成的陣列,取得不定個數的引數

1
2
3
4
5
6
7
8
function foo() {
const arr = Array.prototype.slice.call(arguments);
console.log(arguments); // (1)
console.log(arr); // (2)
}

let testList = foo('hello', 'world', 'bar', 'baz'); // ->類陣列
let testList1 = foo(2, 4, 5, 6, 7); // ->類陣列

物件裡有 length 屬性

1
2
3
4
5
6
7
let objArr1 new Array(5);
objArr1.length;
//objArr1; -> [empty x 5]

// 或是
let objArr2 = Array.from({ length: 5 });
// objArr2; -> [undefined, undefined, undefined, undefined, undefined]

如何辨別一個陣列是類陣列

在大全裡有提供如何測試是否為類陣列的方法:

1
2
3
4
5
6
7
8
9
10
11
12
function isArrayLike(testArr) {
if (
testArr &&
typeof testArr === 'object' &&
isFinite(testArr.length) &&
testArr.length >= 0 &&
testArr.length === Math.floor(testArr.length) &&
testArr.length < 4294967296
)
return true;
else return false;
}

再用上述的函式測試前面兩個類陣列,回傳的都是 true,表示都是類陣列物件。

1
2
console.log(isArrayLike(objArr1)); // true
console.log(isArrayLike(objArr2)); // true

有沒有被類陣列弄得頭很痛?如果是類陣列就無法使用大部分的陣列內建方法,是不是很可惜?下次有機會再來介紹把類陣列轉成一般的陣列的方法吧!

最後附上一張讓人想放空的圖片送給大家,記得週末要放空一下喔!週末愉快~
https://ithelp.ithome.com.tw/upload/images/20190921/20104175z4MbV0ywi8.jpg

All 圖片來源:https://unsplash.com

如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~