當涉及到檢測資料的問題時,我們首先想到的可能就是用typeof來檢測資料型別。
其中typeof返回範例如下:
// 數值
typeof 23 === 'number';
// 字串
typeof '' === 'string';
// 布林值
typeof false === 'boolean';
// Symbols
typeof Symbol() === 'symbol';
// Undefined
typeof undefined === 'undefined';
// 物件
typeof { a: 1 } === 'object';
typeof [1, 2, 4] === 'object';
// 函數
typeof function () { } === 'function';
//注意:
// 下面的例子令人迷惑,非常危險,沒有用處。避免使用它們。
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
由上例我們可以看出,對於Function, String, Number, Undefined等這幾種基本型別來說,我們可以採用typeof檢測。
但是對於陣列或者正則(由一個字元序列形成的搜尋模式)來說,typeof檢測無法滿足,因為兩者的返回型別都是物件object,所以我們還需另找方法…
instanceof可以判斷一個建構函式的prototype屬性所指向的物件是否存在另外一個要檢測物件的原型鏈上,所以用來檢測某物件是否是陣列可能更好不過了,直接通過看返回值true與false直接可以判斷是否是陣列。
程式碼如下(範例):
console.log([] instanceof Array); // true
console.log({ a: 1 }instanceof Array); // false
同樣 由於js中每一個物件都有一個constructor屬性,它參照了初始化該物件的建構函式,比如判斷未知物件的型別。
程式碼如下(範例):
//方法重寫
function isArray(obj) {
return typeof obj == 'object' && obj.constructor == Array
}
// 測試de
console.log(isArray([])); // true
var a = {"a":1};
console.log(isArray(a)); // false
var b = [1,2,3];
console.log(isArray(b)); // true
console.log(isArray(/\d+/g)); // false
如上可以看到,通過呼叫prototype屬性與isArray 方法一般情況下可以判斷是否為陣列的列子
但是這種一般情況真的可以完全判斷嗎?答案當然是否定的,當對於跨框架iframe的時候使用頁面中的陣列時:
程式碼如下(範例):
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray("1","2","3","4","5");
//這個寫法IE下是不支援的,標準瀏覽器firefox,chrome下有
console.log(arr); // 列印出 ["1", "2", "3", "4", "5"]
console.log(arr instanceof Array); // false
console.log(arr.constructor === Array); // false
失敗的關鍵在於iframe元素的跨平臺的特點,使其有一套自己的執行環境,建立的陣列無法共用其prototype屬性,由於無法共用原型鏈,所以無法採用如上兩種方式判斷。
以上三種方法都無法準確判斷物件是否為陣列,有沒有比較準確的方法呢,答案當然是肯定的。
function isArray(obj) {
return Object.prototype.toString.call(obj) == '[object Array]'; //call是用來改變指向的
} //方法重寫
// 程式碼呼叫
//一般情況
console.log(isArray([])); // true
console.log(isArray([1,2,3])); // true
//判斷特殊情況,跨平臺框架
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray("1","2","3","4","5");
console.log(arr); // ["1","2","3","4","5"]
console.log(isArray(arr)); // true ~
這時候,可能又有人要說了,這種原型鏈的方法這麼麻煩,有簡單一點的嗎,當然ECMA-262為我們引入了Array.isArray()方法。
isArray方法用來準確判斷一個值是否為陣列,對於IE9+、 Firefox 4+、Safari 5+、Opera 10.5+和Chrome都可以完美相容,但是對於IE8之前的版本是不支援的。
但是個人感覺用法來說是最為簡便的:
Array.isArray([]) // true
對於判斷一個物件是陣列的問題上,最好的方式如下:
var arr = [1,2,3];
var arr2 = [{ name : 'jack', age : 22 }];
function isArrayFn(value){
// 判斷Array.isArray的相容性
if (typeof Array.isArray === "function") {
return Array.isArray(value);
}else{
return Object.prototype.toString.call(value) === "[object Array]";
// return obj.__proto__ === Array.prototype;
}
}
console.log(isArrayFn(arr)); // true
console.log(isArrayFn(arr2)); // true
補充:原生鏈的方法不僅看起來較為麻煩,而且執行效率也幾乎慢了Array.isArray()一倍,所以我們為了提高程式碼的執行效率,所以我們可以最先判斷Array.isArray()的相容性問題,之後再考慮選取原型鏈的方法。