判斷是否是陣列的幾種方法

遲不子發表於2018-11-09

萬事開頭難,克服自己的拖延症,第一篇js基礎複習篇start!
希望和各位同行交流,同時歡迎各位指出不足和錯誤之處。

首先,typeof肯定是不行的

對於一些基本型別,typeof是可以判斷出資料型別,但是判斷一些引用型別時候,不能具體到具體哪一種型別
再來複習一下typeof的用法:

// 基本型別
typeof 123;  //number
typeof "123"; //string
typeof true; //boolean
typeof undefined; //undefined
typeof null; //object
let s = Symbol;
typeof s; //symbol

// 引用型別
typeof [1,2,3]; //object
typeof {}; //object
typeof function(){}; //function
typeof  Array; //function  Array型別的建構函式
typeof Object; //function  Object型別的建構函式
typeof Symbol; //function  Symbol型別的建構函式
typeof Number; //function  Number型別的建構函式
typeof String; //function  String型別的建構函式
typeof Boolean; //function  Boolean型別的建構函式

複製程式碼

兩種簡單,但是不是十分準確的方法

var obj = [4,67,23];
obj instanceof Array; //return true 
obj.constructor == Array; // return true
複製程式碼

為什麼不準確?

首先來複習一下instanceof用法

  1. 判斷一個例項是否屬於某種型別
function Foo(name) {
    this.name = name;
}
var f = new Foo('zhangsan');
console.log(f instanceof Foo); //true
console.log(f instanceof Object); //true
複製程式碼
  1. 判斷一個例項是否屬於它的父型別
function Person() {};
function Student() {};
var p = new Person();
Student.prototype = p;
var s = new Student();
console.log(s instanceof Student); //true
console.log(s instanceof Person); //true

記憶:
A instanceof C   等價於  A 是否是 C子類,或者後代?
複製程式碼

instanceof 判斷邏輯?

判斷是否是陣列的幾種方法

判斷邏輯翻譯成js程式碼如下:

_instanceof(f, Foo);  

function _instanceof(L, R) {
    var R = R.prototype;
    var L = L.__proto__;
    while( true) {
        if(L == null) {
            return false;
        }
        if(L == R) {
            return true;
        }
        L = L.__proto__;
    }
}
複製程式碼

instanceof 不準確的原因?

程式碼如下:

    var iframe = document.createElement('iframe');
    document.body.appendChild(iframe);

    var arr = [1,2,3];
    xArray = window.frames[0].Array;  //iframe中的建構函式
    var arrx = new xArray(4,5,6);

    console.log(arrx instanceof Array);  //false
    console.log(arrx.constructor == Array);// false

    console.log(Array.prototype == xArray.prototype); //false
    console.log(arr instanceof xArray); //false

    console.log(arrx.constructor === Array);// false
    console.log(arr.constructor === Array);// true
    console.log(arrx.constructor === xArray);// true
    console.log(Array.isArray(arrx));  //true
複製程式碼

解釋:紅寶書,p88

instanceof操作符的問題在於,它假定只有一個全域性環境。如果網頁中包含多個框架,那實際上就存在兩個以上不同的全域性執行環境,從而存在兩個以上不同版本的Array建構函式。
如果你從一個框架向另一個框架傳入一個陣列,那麼傳入的陣列與在第二個框架中原生建立的陣列分別具有各自不同的建構函式。

constructor 不準確的原因?

因為constructor可以被重寫,所以不能確保一定是陣列
example:

    var str = 'abc';
    str.constructor = Array;
    str.constructor === Array // return true
複製程式碼

而很明顯str不是陣列。
而且constructor和instanceof存在同樣問題,不同執行環境下,constructor判斷不正確問題。

方法3 isArray()

最終確定某個值到底是不是陣列,而不管它是在哪個全域性執行環境中建立的,這個方法的用法如下。

if(Array.isArray(value)){
    return true;
}
複製程式碼

方法4 Object.prototype.toString

如果在尚未實現isArray方法的瀏覽器中準確監測陣列,我們需要用到Object.prototype.toString方法來判斷,每一個繼承自Object的物件都擁有toString的方法。

if(!Array.isArray){
    Array.isArray = function(arg){
        return Object.prototype.toString.call(arg)==='[object Array]'
    }

}
複製程式碼

自己可以封裝一個獲取變數型別的函式

function getType(obj) {
    return Object.prototype.toString.call(obj).slice(8,-1);
}

var a = [1,2,3];
console.log(getType(a)); //Array 

var b = function(){};
console.log(getType(b)); //Function
複製程式碼

參考文章

JavaScript instanceof 運算子深入剖析
javascript 判斷變數是否是陣列(Array)

相關文章