iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 8
3
Day 8

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

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

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

判別變數是否為陣列

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

// 陣列常値 // 數字陣列
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)

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

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

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

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

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

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判別,再確認瀏覽器支不支援這個判別方法,如果不支援,就用另一種方式判別。

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

用哪一種?

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


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


上一篇
JS 如何讀取和寫入陣列 Array 元素
下一篇
JS 如何轉型別為陣列 Array
系列文
JavaScript之一定要了解的 Array 與方法34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Askie Lin
iT邦新手 5 級 ‧ 2019-09-23 13:15:55

讚,有學到!

tsuifei iT邦新手 4 級 ‧ 2019-09-23 14:17:18 檢舉

謝謝 Askie ! 發現參加鐵人賽真的很補腦,哈!

我要留言

立即登入留言