如何檢查JavaScript變量的類型

JavaScript基本數據類型有5種:字符串、數字、布爾、null、undefined。 用戶定義的類型(object)並沒有類的聲明,因此繼承關係只能通過構造函數和原型鏈來檢查。 如何檢查一個變量的類型?以下僅供參考!

如何檢查JavaScript變量的類型

先給結論:

如果你要判斷的是基本數據類型或JavaScript內置對象,使用toString; 如果要判斷的時自定義類型,請使用instanceof。

不同的編程語言都有自己的方式來提供類型信息,例如C#的反射、C++的Traits, JavaScript提供類型信息的方式更加靈活,因而也容易產生很多誤用。 下面來分析常見類型檢查手段的區別:typeof, instanceof, constructor, toString。

如果你在尋找類型轉換的解決方案,而非類型檢查,請移步JavaScript類型轉換。

typeof

typeof 操作符返回的是類型字符串,它的返回值有6種取值:

typeof 3 // "number"

typeof "abc" // "string"

typeof {} // "object"

typeof true // "boolean"

typeof undefined // "undefined"

typeof function(){} // "function"

所有對象的typeof都是"object",不能用於檢測用戶自定義類型。 比如Date, RegExp, Array, DOM Element的類型都是"object":

typeof [] // "object"

typeof還有一個知名的bug:

typeof null // "object"

null是基本數據類型,它的類型顯然是Null。其實這也反映了null的語義, 它是一個空指針表示對象爲空,而undefined才表示什麼都沒有。 總之,typeof只能用於基本數據類型檢測,對於null還有Bug。

instanceof

instanceof操作符用於檢查某個對象的原型鏈是否包含某個構造函數的prototype屬性。例如:

obj instanceof Widget

obj的原型鏈上有很多對象(成爲隱式原型),比如:obj.__proto__, obj.__proto__.__proto__, ...如果這些對象裏存在一個p === otype,那麼instanceof結果爲true,否則爲false。

instanceof是通過原型鏈來檢查類型的,所以適用於任何"object"的類型檢查。

// 比如直接原型關係

function Animal(){ }

(new Animal) instanceof Animal // true

// 原型鏈上的.間接原型

function Cat(){}

otype = new Animal

(new Cat) instanceof Animal // true

instanceof也可以用來檢測內置兌現,比如Array, RegExp, Object, Function:

[1, 2, 3] instanceof Array // true

/abc/ instanceof RegExp // true

({}) instanceof Object // true

(function(){}) instanceof Function // true

instanceof對基本數據類型不起作用,因爲基本數據類型沒有原型鏈。

3 instanceof Number // false

true instanceof Boolean // false

'abc' instanceof String // false

null instanceof XXX // always false

undefined instanceof XXX // always false

但你可以這樣:

new Number(3) instanceof Number // true

new Boolean(true) instanceof Boolean // true

new String('abc') instanceof String // true

但這時你已經知道數據類型了,類型檢查已經沒有意義了。

constructor

constructor屬性返回一個指向創建了該對象原型的函數引用。需要注意的是,該屬性的值是那個函數本身。例如:

function Animal(){}

var a = new Animal

tructor === Animal // true

constructor不適合用來判斷變量類型。首先因爲它是一個屬性,所以非常容易被僞造:

var a = new Animal

tructor === Array

tructor === Animal // false

另外constructor指向的是最初創建當前對象的函數,是原型鏈最上層的那個方法:

function Cat(){}

otype = new Animal

function BadCat(){}

otype = new Cat

(new BadCat)tructor === Animal // true

tructor === Function // true

與instanceof類似,constructor只能用於檢測對象,對基本數據類型無能爲力。 而且因爲constructor是對象屬性,在基本數據類型上調用會拋出TypeError異常:

tructor // TypeError!

tructor // TypeError!

與instanceof不同的是,在訪問基本數據類型的屬性時,JavaScript會自動調用其構造函數來生成一個對象。例如:

(3)tructor === Number // true

tructor === Boolean // true

'abc'tructor === String // true

// 相當於

(new Number(3))tructor === Number

(new Boolean(true))tructor === Boolean

(new String('abc'))tructor === String

這種將一個值類型轉換爲對象引用類型的機制在其他語言中也存在,在C#中稱爲裝箱(Boxing)。

跨窗口問題

我們知道Javascript是運行在宿主環境下的,而每個宿主環境會提供一套ECMA標準的內置對象,以及宿主對象(如window, document),一個新的窗口即是一個新的宿主環境。 不同窗口下的內置對象是不同的實例,擁有不同的內存地址。

而instanceof和constructor都是通過比較兩個Function是否相等來進行類型判斷的。 此時顯然會出問題,例如:

var iframe = teElement('iframe');

var iWindow = entWindow;

ndChild(iframe);

y === Array // false

// 相當於

y === y // false

因此iWindow中的數組arr原型鏈上是沒有y的。請看:

e('

');

instanceof Array // false

instanceof y // true

toString

toString方法是最爲可靠的類型檢測手段,它會將當前對象轉換爲字符串並輸出。 toString屬性定義在otype上,因而所有對象都擁有toString方法。 但Array, Date等對象會重寫從otype繼承來的toString, 所以最好用ring來檢測類型。

toString = ring;

(new Date); // [object Date]

(new String); // [object String]

(Math); // [object Math]

(3); // [object Number]

([]); // [object Array]

({}); // [object Object]

// Since JavaScript 1.8.5

(undefined); // [object Undefined]

(null); // [object Null]

toString也不是完美的,它無法檢測用戶自定義類型。 因爲otype是不知道用戶會創造什麼類型的, 它只能檢測ECMA標準中的那些內置類型。

(new Animal) // [object Object]

因爲返回值是字符串,也避免了跨窗口問題。當然IE彈窗中還是有Bug,不必管它了。 現在多少人還在用IE?多少人還在用彈窗?

和ring類似地,ring也有類似功能, 不過它的this只能是Function,其他類型(例如基本數據類型)都會拋出異常。

總結

typeof只能檢測基本數據類型,對於null還有Bug;

instanceof適用於檢測對象,它是基於原型鏈運作的;

constructor指向的是最初創建者,而且容易僞造,不適合做類型判斷;

toString適用於ECMA內置JavaScript類型(包括基本數據類型和內置對象)的類型判斷;

基於引用判等的類型檢查都有跨窗口問題,比如instanceof和constructor。

總之,如果你要判斷的是基本數據類型或JavaScript內置對象,使用toString; 如果要判斷的時自定義類型,請使用instanceof。

有時Duck Typing的方式也非常可行,貌似已經成爲了前端的慣例。 比如jQuery是這樣判斷一個Window的:

isWindow: function(obj){

return obj && typeof obj === 'object' && "setInterval" in obj;

}

另外DOM Element的類型檢測也可以通過上述的方法來完成,但沒有一種方法在任何瀏覽器上都可行。 DOM Element的類型檢測可以參見這篇文章

同時發表在: