JavaScript 的數據類型分為兩類:原始類型(基本類型)和對象類型(引用類型)。原始類型包括數字、字符串和布爾值,另外有兩個特殊的原始值:null 和 undefined,除此之外的都是對象。對象還包括兩種特殊的對象:數組和函數。
下面所有代碼表達式如果返回值為 true 表示判斷成立,否則不成立,變量 obj 表示需要判斷的值。
通用方法
使用 typeof 運算符
判斷數據類型可以使用 typeof 運算符,返回值是一個代表數據類型的字符串(注意是字符串,而且是小寫的):
typeof 1 // 'number'
typeof 'abc' // 'string'
typeof false // 'boolean'
typeof undefined // 'undefined'
typeof null // 'object'
typeof {x: 1} // 'object'
typeof [1, 2, 3] // 'object'
typeof function() {} // 'function'
typeof 運算符可以有效判斷數字、字符串、布爾值和 undefined 等原始類型,不過在面對數組和對象時就無能為力了。
借用 Object.prototype.toString() 方法
借用 Object.prototype.toString() 方法可以得到一個表示對象的類型的字符串:
var toString = Object.prototype.toString;
toString.call('abc') // '[object String]'
toString.call(true) // '[object Boolean]'
toString.call([]) // '[object Array]'
toString.call({}) // '[object Object]'
toString.call(/./) // '[object RegExp]'
toString.call(new Date) // '[object Date]'
toString.call(Math) // '[object Math]'
使用該方法可以有效判斷數組、函數、日期、正則表達式等對象類型(引用類型)。在 ECMAScript 5 中還可以用這個方法來判斷 null
和 undefined:
toString.call(null) // '[object Null]'
toString.call(undefined) // '[object Undefined]'
下面是一些特殊情況。
原始類型(基本類型)
數字
使用 typeof 運算符可以判斷任意數字、NaN 或者 Infinity:
typeof NaN // 'number'
typeof Infinity // 'number'
如果要排除 NaN 和 Infinity 可以使用 isFinite() 方法,不過 isFinite() 方法試圖將一些非數字類型轉換為數字,因此需要雙重保險:
typeof obj === 'number' && isFinite(obj)
上面的表達式如果返回為 true 則保證了變量 obj 是數字類型的同時不是 NaN 或者 Infinity,畢竟我們不希望這兩個特殊數值參與數學運算。ECMAScript 6 增加的 Number.isFinite() 方法有同樣效果。
整數
判斷一個數是整數並且在安全范圍內,利用整數取整后還是與自身相等的特點:
typeof obj === 'number' && isFinite(obj)
&& obj > -9007199254740992
&& obj < 9007199254740992
&& Math.floor(obj) === obj
NaN
全局的 isNaN() 方法也試圖將一些非數字類型隱式轉換為數字,如果轉換成功,它會認為這個值是一個數字,否則會認為這是一個 NaN:
isNaN(NaN) // true
isNaN(0/0) // true 0 除以 0 的結果為 NaN
isNaN('1') // false 字符串 '1' 可以隱式轉換為數字 1
isNaN(true) // false 布爾值 true 可以隱式轉換為數字 1
isNaN([]) // false 空數組可以隱式轉換為數字 0
isNaN(Infinity) // false
isNaN('abc') // true
isNaN(undefined) // true
字符串 'abc' 和 undefined 都不能隱式轉換為一個數字,所以被判斷為是一個 NaN。
NaN 是一個特殊數值,它不等於任何值,甚至不等於它自己,因此判斷一個值為 NaN 的最好方式是判斷它是一個數字類型同時不等於自身:
typeof obj === 'number' && obj != +obj
ECMAScript 6 增加的 Number.isNaN() 方法更好地解決了這個問題,只有值為 NaN 的時候才會返回 true:
Number.isNaN(NaN) // true
Number.isNaN(Number.NaN) // true
Number.isNaN(0/0) // true
Number.isNaN(Infinity) // false
Number.isNaN('abc') // false
Number.isNaN(undefined) // false
可以看出 Number.isNaN() 方法和 isNaN() 方法是不一樣的。Number.isNaN() 方法僅用於判斷是否是特殊值 NaN。
布爾值
布爾值不是 true 就是 false,可以使用 typeof 運算符,也可以像下面這樣判斷:
obj === true || obj === false
Undefined
在 ECMAScript 3 中 undefined 是可讀寫的,所以直接與 undefined 作比較返回的結果不一定是准確的,像這樣 var undefined = 1 在有些實現中是可以改變其值的,此時再與之做比較得到的結果就有點出人意料了,通常情況下還是使用 typeof 運算符來判斷:
typeof obj === 'undefined'
不過使用 typeof 運算符有一個不好的地方是不能區分未定義的變量和值為 undefined 的變量(兩者還是有區別的),另外一種方式是使用 void 運算符,因為它的運算結果總是返回 undefined:
obj === void 0
Null
使用 typeof 運算符判斷 null 將會返回 'object',這明顯不是想要的,所以最好的方式是直接與 null 值進行比較:
obj === null
這里必須使用 ===,因為 undefined == null 也會返回 true。
存在判斷
對值為 null 或 undefined 的變量讀取屬性時會引發錯誤,因此有時候需要做存在判斷,簡單地使用 if 語句來判斷,會將那些可以隱式轉換為 false 的值也一概排除掉了,比如數字0、空字符串、空數組(這里有個錯誤,空數組單獨放在 if 語句里面將會轉換為 true,而作比較的時候是與 false 相等的,比如 [] == false)之類的,它們都可以隱式轉換為 false,因為 undefined == null 會返回 true,而和其它任何非 null 或者 undefined 的值比較都會返回 false,所以更好的辦法是直接與 null 值做比較:
if (obj != null) {
obj.property;
}
這樣就可以判斷變量 obj 既不是 undefined 也不是 null,或者像下面這樣判斷:
typeof obj !== 'undefined' && obj !== null
通過存在判斷才可以放心使用 . 語法獲取屬性。
對象類型(引用類型)
對象
要區別 null 和其它對象可以像下面這樣判斷,因為 null 值可以隱式轉換為 false:
obj && typeof obj === 'object'
這樣判斷就可以把 null 給排除掉,變量 obj 是對象或者數組或者其它對象(不包括函數)。下面是另外一種方法:
obj === Object(obj)
使用 Object() 方法如果傳入的參數不是對象將會被轉換為對象,否則,只是簡單地將傳入的參數返回。該方法可以判斷所有對象,包括函數。
數組
判斷數組的方法:
Object.prototype.toString.call(obj) === '[object Array]'
ECMAScript 5 增加了數組檢測的原生方法:
Array.isArray(obj)
函數
雖然 typeof 運算符將函數特別對待了,但是使用 typeof 運算符在有些實現中不是函數的也會返回 'function',因此還是使用如下方法來判斷函數:
Object.prototype.toString.call(obj) === '[object Function]'
正則表達式
使用 typeof 運算符判斷正則表達式,一般都會返回 'object',不過也有一些實現會返回 'function',所以,還是借用 Object.prototype.toString 方法來判斷:
Object.prototype.toString.call(obj) === '[object RegExp]'
