判斷JS資料型別的四種方法
說到資料型別,我們先說一下JavaScript 中常見的幾種資料型別:
基本型別:string,number,boolean
特殊型別:undefined,null
引用型別:Object,Function,Function,Array,RegExp,Date,...
很多時候我們都需要通過判斷變數的資料型別來進行下一步操作,下面我們介紹常用的4種方法:
1、typeof
typeof 返回一個表示資料型別的字串,返回結果包括:number、boolean、string、object、undefined、function等6種資料型別。
1 2 3 4 5 6 7 8 9 |
typeof '' ; //
string 有效
typeof 1; //
number 有效
typeof true ; //boolean
有效
typeof undefined; //undefined
有效
typeof null ; //object
無效
typeof []
; //object
無效
typeof new Function(); //
function 有效
typeof new Date(); //object
無效
typeof new RegExp(); //object
無效
|
typeof 可以對JS基礎資料型別做出準確的判斷,而對於引用型別返回的基本上都是object, 其實返回object也沒有錯,因為所有物件的原型鏈最終都指向了Object,Object是所有物件的`祖宗`。 但當我們需要知道某個物件的具體型別時,typeof 就顯得有些力不從心了。
2、instanceof
instanceof 是用來判斷 A 是否為 B 的例項對,表示式為:A instanceof B,如果A是B的例項,則返回true,否則返回false。 在這裡需要特別注意的是:instanceof檢測的是原型,我們用一段虛擬碼來模擬其內部執行過程:
1 2 3 4 5 6 7 8 9 |
instanceof
(A,B) = {
var L
= A.__proto__;
var R
= B.prototype;
if (L
=== R) {
//A的內部屬性__proto__指向B的原型物件
return true ; }
return false ;
}
|
從上述過程可以看出,當 A 的 __proto__ 指向 B 的 prototype 時,就認為A就是B的例項,我們再來看幾個例子:
1 2 3 4 5 6 7 8 9 10 |
[]
instanceof Array; //true
{}
instanceof Object; //true
new Date()
instanceof Date; //true
function
Person(){};
new Person()
instanceof Person;
[]
instanceof Object; //true
new Date()
instanceof Object; //true
new Person
instanceof Object; //true
|
我們發現,雖然 instanceof 能夠判斷出 [] 是Array的例項,但它認為 [] 也是Object的例項,為什麼呢? 我們來分析一下[]、Array、Object 三者之間的關係: 從instanceof 能夠判斷出 [].__proto__ 指向 Array.prototype, 而 Array.prototype.__proto__ 又指向了Object.prototype,Object.prototype.__proto__ 指向了null,標誌著原型鏈的結束。因此,[]、Array、Object就形成了如下圖所示的一條原型鏈:
從原型鏈可以看出,[] 的 __proto__ 直接指向Array.prototype, 間接指向Object.prototype, 所以按照 instanceof 的判斷規則,[] 就是Object的例項。當然,類似的new Date()、new Person() 也會形成這樣一條原型鏈,因此,instanceof 只能用來判斷兩個物件是否屬於原型鏈的關係, 而不能獲取物件的具體型別。
3、constructor
當一個函式F被定義時,JS引擎會為F新增prototype原型,然後再在prototype上新增一個constructor屬性,並讓其指向F的引用。如下所示:
當執行 var f = new F() 時,F被當成了建構函式,f是F的例項物件,此時F原型上的constructor傳遞到了f上,因此f.constructor == F
可以看出,JS在函式F的原型上定義了constructor,當F被當作建構函式用來建立物件時,建立的新物件就被標記為了“F” 型別,使得新物件有名有姓,可以追溯。
同理,JS中的資料型別也遵守這個規則:
細節問題:
- null和undefined是無效的物件,因此是不會有constructor存在的,這兩種型別的資料需要通過typeof來判斷。
- JS物件的constructor是不穩定的,這個主要體現在自定義物件上,當開發者重寫prototype後,原有的constructor會丟失,constructor會預設為Object
為什麼變成了Object?
prototype被重新賦值的是一個{}, {}是new Object()的字面量,因此new Object()會將Object原型上的constructor傳遞給{},也就是Object本身。
因此,為了規範,在重寫物件原型時一般都需要重新給constructor賦值,以保證例項物件的型別不被改寫。
4、Object.prototype.toString
toString是Object原型物件上的一個方法,該方法預設返回其呼叫者的具體型別,更嚴格的講,是 toString執行時this指向的物件型別, 返回的型別格式為[object,xxx],xxx是具體的資料型別,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有物件的型別都可以通過這個方法獲取到。
1 2 3 4 5 6 7 8 9 10 11 12 |
Object.prototype.toString.call( '' )
; //
[object String]
|