0%

判別是否為陣列 Array

Day 08

如果你不是台灣的國民,就不能在台灣投票

Javascript 是弱型別語言,也因為這個特性,在處理資料時 JavaScript 很可能的很好心,一不小心就把資料自動轉型成另一個資料型態了,所以為了避免在使用陣列內建方法或處理陣列時出現錯誤,常常會使用許多方法來判別是否為陣列。如果元素不是陣列,就無法使用陣列專用的函式或做些陣列的處理,因此才會有確認某元素的原型是陣列的需要。

陣列 Array 在 JavaScript 裡的型別是object,這點可以透過 typeof 這個運算符回傳的資訊,來確認某一資料是否為陣列。但是,在物件裡的某一元素是否為陣列,又該怎麼判別? 以下有幾種方法:

判別變數是否為陣列

這邊有四個同是陣列,但不同形態內容的元素,還有一個非陣列的物件變數,我們可以拿它們來測試。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 陣列常値 // 數字陣列
const arr1 = [1, 2, 3];

// 非同型陣列
const arr2 = ['one', 2, 'three'];

// 陣列裡有陣列
const arr3 = [
[1, 2, 3],
['one', 2, 'three']
];

// 非同型陣列
const arr4 = [
{ name: 'Tsuifei', type: 'object', luckyNumber: [5, 7, 13, 42] },
[
{ name: 'Philippe', type: 'object' },
{ name: 'Ayda', type: 'object' }
],
1,
function too() {
return 'array can contain function too';
},
'three'
];

// 物件
const me = { name: 'Tsuifei', type: 'object', luckyNumber: [5, 7, 13, 42] };

isArray 小而美

最簡單的陣列判斷語法 isArray,用的是內建 Array 物件中的 isArray,是個 ES5 的標準方法:
Array.isArray(variable)

1
2
3
4
5
6
Array.isArray(arr1); // true
Array.isArray(arr2); // true
Array.isArray(arr3); // true
Array.isArray(arr4); // true

Array.isArray(me); //false

constructor === Array 輕而巧

使用constructor,這個是在 Chrome 瀏覽器中效能最佳的判斷方法,它是直接用物件的建構式來判斷:
variable.constructor === Array

1
2
3
4
5
arr1.constructor === Array; // true
arr2.constructor === Array; // true
arr3.constructor === Array; // true
arr4.constructor === Array; // true
me.constructor === Array; // false

判別物件中的陣列

constructor === Array

與上方一個相同,只是針對物件中的陣列來使用,如果要判別物件中的其中屬性是否為陣列,可以先判斷這個屬性是否存在,再繼續判斷這個值是否為陣列,我們以物件型態的變數來測驗,如下:
variable.value && variable.value.constructor === Array

1
2
3
4
5
6
7
8
9
const me = {
name: 'Tsuifei',
type: 'object',
luckyNumber: [5, 7, 13, 42]
};

me.name && me.name.constructor === Array; // false
me.type && me.type.constructor === Array; // false
me.luckyNumber && me.luckyNumber.constructor === Array; // true

instanceof 物件的實例

先來看看 MDN 怎麼解釋:MDN instanceof
instanceof 運算符用於測試建構式函式的 prototype 屬性,是否出現在物件的原型鏈中的任何位置,也就是說instanceof 運算符是用於判斷是否為某個建構式new的實例,優點為語法簡潔清楚。

但是缺點還是有的,雖然只要是在原型鏈上面的類別,都會回傳true,但是建構是有可能因為某些原因而被修改,改變之後的值很有可能不存在於原型鏈上,這時判別回傳得到的值就會成為false

1
2
3
4
function fnuc() {}
let testF = new fnuc();
testF instanceof Array;
// false testF 不是一個陣列,它是一個建構式宣告出來的實例(物件)

instanceof不只可以判別陣列,也可以拿來判別其他的型別,如string

1
2
3
4
5
6
7
8
9
var arr5 = [1, 2, 3];
arr5 instanceof Array; // true

var arrObj = new Array([1, 2, 3]);
arrObj instanceof Array; // true

// 也適用於其他型別的判別
var arrObj = new String('hello world');
arrObj instanceof String; // true

instanceof有個缺點,就是處理的windowiframe時的變數會失效,詳細的解說在MDN有較詳細的說明。

toString.call

==推薦使用==
網路上推薦這種方式判別的頗多,原因應該是這種方式是所有情況都可以正確判別的一種,且可適用各種狀況,也可以判斷陣列以外的其他特別物件,唯一缺點是效率最差。
在 JavaScript: The Definitive Guide, 6th Edition 書中有提到,Array.isArray 其實就是用這個方式實作的。
Object.prototype.toString.call(variable) === '[object Array]'

網路上也有人寫成一支判斷陣列終極解決方案,先用typeof判別,再確認瀏覽器支不支援這個判別方法,如果不支援,就用另一種方式判別。

1
2
3
4
5
6
7
8
9
10
11
12
13
const arr6 = [1, 2, 3];
const arr7 = 42;
function isArrayFn(obj) {
// 包成函式
if (typeof Array.isArray === 'function') {
return Array.isArray(obj); // 如果瀏覽器支援就用 isArray() 方法
} else {
// 否則就使用 toString 方法
return Object.prototype.toString.call(obj) === '[object Array]';
}
}
isArrayFn(arr6); // true
isArrayFn(arr7); // false

用哪一種?

這幾個方式的選擇,網路上的前輩建議是==只要學最後一種==就行了(就是最後一種),可以正確判斷並應用在各種情況為首要條件,有時候正確性比效能快更為重要,更何況它其實是萬用的,除了陣列之外也可以用於其它的判斷情況。雖然它的語法對初學者來說,可能無法在此時完全理解 在說我嗎?,不過就先知道要這樣用就行了。


寫完才發現這篇更詳細的介紹,有興趣的可以轉台過去看,真的很詳細,推~

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