|
|
|
|
|
|
“數組是類似列表的對象,其原型具有執行遍歷和變異操作的方法。” — MDN 文檔
如何在 JavaScript 中檢查對象是否數組?本文將詳細介紹 5 種方法,并比較它們的優缺點:
方法一:Array.isArray([])
ECMAScript 5 (ES5) 引入了 Array.isArray() 方法來檢查數組,因為 typeof 無法將數組與其他對象區分開來,例如內置對象 Date 和 RegExp。
使用 Array.isArray() 也有助于確保我們的對象不為空,因為由于長期存在的錯誤,null 具有“對象”類型。
下面是使用 Array.isArray([]) 檢查數組的示例:

方法二:Object.prototype.toString.call([])
冗長的 JavaScript 語句 Object.prototype.toString.call() 可以區分數組和其他類型的對象,因為它返回的字符串比 typeof 更詳細地指定了對象類型。
因為此方法適用于任何對象,所以我稱其為 JavaScript 中類型檢查的最佳方法。這是一個例子:

雖然冗長,但此方法適用于任何原始類型和任何對象。它總是返回變量的構造函數的名稱。
換句話說,Object.prototype.toString.call() 有點像 instanceof 的逆向,盡管它在 iframe 中運行良好。
上述 isArray() 函數的行為應該與內置的 Array.isArray() 函數相同。
這里要注意的一點是 typeof {} 返回“object”(小寫),但 Object.prototype.toString.call({}).slice(8,-1) 返回“Object”(大寫)對象 {}和數組 [] 的“Array”(大寫)。
與所有這些方法一樣,如果尚未聲明變量,此方法將不起作用。稍后我將討論檢查未聲明的變量。
方法三:[] instanceof 數組
使用關鍵字 instanceof 可用于檢查數組或任何類型的 JavaScript 對象。
“instanceof 運算符測試構造函數的原型屬性是否出現在對象原型鏈的任何位置。” — MDN 文檔
語法很簡單,如下代碼示例所示:

但請注意,iframe 可能會破壞這種行為,如 Mozilla 開發人員網絡文檔中 Array.isArray 中所述:
instanceof vs isArray
在檢查 [an] Array 實例時,Array.isArray優于instanceof,因為它通過 iframe 工作。— MDN 文檔
這意味著我們可能根本不想使用 instanceof 來檢查數組,以防萬一我們的 JavaScript 代碼最終在 iframe 中運行。
方法四:[].constructor
這是一個類似于 instanceof 的方法——調用 JavaScript 對象的 .constructor 屬性。
.constructor 屬性將返回構造函數,對于數組,它是函數 Array()(即 JavaScript 類 Array)。
訪問該函數的 .name 屬性將給出字符串“Array”,該字符串可用于形成對數組是否存在的簡單檢查。
由于 .constructor 屬性返回函數 Array()(即 JavaScript 類 Array),因此也可以直接將其與全局 Array 對象(即返回的函數 Array() 所引用的對象)進行比較。
換句話說,實際上不必使用 .name 屬性:[].constructor===Array 等價于 [].constructor.name==="Array"。
這是一個代碼示例:

與 Object.prototype.toString.call() 類似,訪問 .constructor 屬性將適用于任何類型的 JavaScript 值,包括原語——盡管您不能訪問 .constructor 以獲取未定義或空值。
(請注意,instanceof 關鍵字適用于對象,但不適用于基元。當然,instanceof 在 iframe 中存在錯誤。)
正如我們在上面看到的,使用沒有 null 檢查的 .constructor 會導致 null 和 undefined 的 TypeError — 與 Array.isArray() 相比的缺點,后者只會為這兩個值返回 false。
并且,與到目前為止介紹的任何方法一樣,如果想嘗試訪問未聲明的變量,它們將引發 ReferenceError。
.constructor 是可變的在繼續之前,值得注意的是 .constructor 并不健壯,因為它是一個可以在以后覆蓋的對象屬性。
請記住,如果你出于任何原因通過原型覆蓋您的構造函數,則 arr.constructor === Array 測試將返回 false。Array.isArray(arr) 仍然返回 true。
所以只要記住一個對象的 .constructor 屬性是“可變的”——它可能已經在代碼中的某個地方從它的原始值改變了。
方法 5:&& 和 [].constructor(空檢查?。?/span>
這是一個簡潔的單行代碼,它將在檢查數組的同時檢查非空值:[] && [].constructor === Array。
null 和 undefined 都是false,這意味著它們在條件語句中評估為false,但所有對象都是true,包括空數組。檢查 [] && [].constructor === Array 將為 null 或未定義的值返回 false,而單獨的 .constructor 會引發錯誤。
包含邏輯 AND (&&) 運算符的優點是可以避免由于 null 和 undefined 沒有屬性而發生的 TypeError。這是有效的,因為 && 是一個“短路運算符”。通過使用邏輯 AND (&&),我們在嘗試訪問 .constructor 屬性之前檢查該值是否為true。這是一個代碼示例:

為了提高代碼的可讀性,你可以考慮使用松散相等(==)來顯式地檢查空值:[] != null && [].constructor。使用 !=(松散相等運算符)意味著 null 和 undefined 彼此相等。
更明確的檢查將使用嚴格相等:[] !== null && [] !== undefined && [].constructor === Array。許多 JavaScript 程序員寧愿從不使用松散相等,因為 == 的規則令人困惑。
使用 && 和 .constructor 對 null 和 undefined 的工作方式與 Array.isArray() 的效果相同:它返回 false,正如你所希望的那樣。
但是,未聲明的變量在嘗試訪問 .constructor 屬性時仍會引發 ReferenceError。你可以在數組檢查之前使用 typeof 檢查該值是否“undefined”以解決該問題。
如果數組變量實際上是未聲明的怎么辦?
你可能不確定是否實際上已經聲明了可能是數組的變量。讓我簡單談談檢查未聲明的數組。
提醒一下,訪問尚未聲明的變量將引發 ReferenceError,而已聲明但未分配特定值的變量將具有 undefined 值。
值得慶幸的是,typeof 關鍵字將為尚未聲明的變量返回“undefined”,與未定義的值相同,但不會拋出 ReferenceError,因為該變量還沒有被聲明。
這意味著我們可以將 Array.isArray() 包裝在 typeof 調用中,以使其對未聲明的變量具有魯棒性。這是一個例子:

或者,我們可以使用 try...catch 塊來捕獲潛在的 ReferenceError,但 typeof 對未聲明的變量同樣有效。
如何在 JavaScript 中檢查空數組?
相反,如果我們想檢查一個數組是否為空,我們可以檢查它的 .length 屬性——一個空數組的 .length 為 0。
同樣,我們需要確保我們正在使用一個已聲明的變量,該變量已經分配了一個絕對是數組的值。
但是,假設我們從 Array.isArray([]) 得到 true,那么 [].length > 0 將確認我們的數組不為空。這是一個代碼片段:

同樣,我們正在利用 && 作為短路運算符。因為它在錯誤陳述上“短路”,所以我們永遠不會達到上面示例中的 .length 調用。這正是我們想要的,因為 .length 不適用于大多數原語,如數字或其他類型的對象。
總結
本文詳細介紹了5 種不同的檢查 JavaScript 數組的方法。我在編碼時通常使用 Array.isArray() ,有幾個原因:
有時,在我擔心未聲明變量的罕見情況下,我會將數組檢查包含在 if(typeof !== "undefined") 語句中。
參考文章
