要想判斷數據類型,首先要知道數據類型的分類。數據類型分爲基本數據類型和引用數據類型。正則表達式
基本數據類型有 五 種,ES6中新加了第 六 種基本數據類型——Symbol 類型。編程
引用類型數據也會統稱爲對象,即廣義的對象,一般除了基本數據類型的其它數據都屬於引用類型數據。數組
{key1:value1, key2:value2,...}
[value1,value2,...]
typeof
返回字符串,number
、string
、boolean
、symbol
、undefined
、function
,全部其它的引用類型數據都返回 object
,null
也返回 object
。瀏覽器
typeof 666 // "number" typeof 'dora' // "string" typeof true // "boolean" typeof Symbol() // "symbol" typeof undefined // "undefined" typeof null // "object" typeof function(){} // "function" typeof [] // "object" typeof /dora/ // "object"
可利用判斷 undefined
來檢查一個沒有聲明的變量,而不報錯。實際編程中,這個特色一般用在判斷語句中。函數
// 錯誤的寫法 if (v) { // ... } // ReferenceError: v is not defined // 正確的寫法 if (typeof v === "undefined") { // 這種寫法在 v 沒有聲明的時候不會報錯。 }
注意this
ES6中引入了 let
以後,這個方法也不是萬能的了。當變量在代碼塊內用 let
聲明的時候,會造成「暫時性死區」(temporal dead zone,簡稱 TDZ),此時這個方法就沒用了,typeof 仍是會報錯。prototype
typeof x; // ReferenceError let x;
不能準確的判斷引用類型數據的具體類型,除了函數外,其他的都是返回object
。code
typeof {} // "object" typeof [] // "object"
此時,在須要判斷數組或者對象時,就不適用了。regexp
Object.prototype.toString()
方法返回對象的類型字符串,所以能夠用來判斷一個值的類型。對象
var obj = {}; obj.toString() // "[object Object]"
上面代碼調用空對象的toString方法,結果返回一個字符串 object Object
,其中第二個Object表示該值的 構造函數。
因爲實例對象可能會自定義toString方法,覆蓋掉 Object.prototype.toString
方法,因此爲了獲得類型字符串,最好直接使用Object.prototype.toString
方法。經過函數的call
方法,能夠在任意值上調用這個方法,幫助咱們判斷這個值的類型。
Object.prototype.toString.call(value)
上面代碼表示對value這個值調用Object.prototype.toString
方法。
不一樣數據類型的Object.prototype.toString
方法返回值以下:
[object Number]
。[object String]
。[object Boolean]
。[object Undefined]
。[object Null]
。[object Symbol]
。[object Array]
。[object Arguments]
。[object Function]
。[object Error]
。[object Date]
。[object RegExp]
。[object Object]
。Object.prototype.toString.call(2) // "[object Number]" Object.prototype.toString.call('') // "[object String]" Object.prototype.toString.call(true) // "[object Boolean]" Object.prototype.toString.call(undefined) // "[object Undefined]" Object.prototype.toString.call(null) // "[object Null]" Object.prototype.toString.call(Symbol()) // "[object Symbol]" Object.prototype.toString.call(Math) // "[object Math]" Object.prototype.toString.call({}) // "[object Object]" Object.prototype.toString.call([]) // "[object Array]"
利用這個特性,能夠封裝一個比typeof
運算符更準確的類型判斷函數。
var type = function (o){ var s = Object.prototype.toString.call(o); return s.match(/\[object (.*?)\]/)[1].toLowerCase(); }; type({}); // "object" type([]); // "array" type(5); // "number" type(null); // "null" type(); // "undefined" type(/dora/); // "regexp" type(new Date()); // "date"
在上面這個type函數的基礎上,還能夠加上專門判斷某種類型數據的方法。
var dataArr = ['Null', 'Undefined', 'Object', 'Array', 'String', 'Number', 'Boolean', 'Function', 'RegExp']; dataArr.forEach(function (t) { type['is' + t] = function (o) { return type(o) === t.toLowerCase(); }; }); type.isObject({}); // true type.isNumber(NaN); // true type.isRegExp(/abc/); // true
instanceof
運算符返回一個布爾值,表示對象是否爲某個構造函數的實例。
function People(){} var person = new People(); person instanceof People // true
遍訪對象的原型鏈上的每一個原型對象,若是遍訪到這個原型對象,是某個構造函數的prototype
,那麼就認爲對象是這個構造函數的實例,返回true。所以同一個實例對象,可能會對多個構造函數都返回true,由於繼承的子類實例也是父類的實例。
var d = new Date(); d instanceof Date // true d instanceof Object // true
特殊狀況
有一種特殊狀況,就是左邊對象的原型鏈上,只有null對象。這時,instanceof
判斷會失真。
var obj = Object.create(null); typeof obj // "object" obj instanceof Object // false
上面代碼中,Object.create(null)
返回一個新對象obj
,它的原型是null
。右邊的構造函數Object
的prototype
屬性,不在左邊的原型鏈上,所以instanceof
就認爲obj
不是Object
的實例。
只要一個對象的原型不是null
,instanceof
運算符的判斷就不會失真。
instanceof
運算符只能用於對象,不適用原始類型的值,且對於undefined
和null
,instanceof
運算符老是返回false
。
'hello' instanceof String // false undefined instanceof Object // false null instanceof Object // false
可用於對象,不管是 JavaScript 內置對象或是自定義構造函數生成的對象,均可進行判斷。
[] instanceof Array // true ({}) instanceof Object // true (function(){}) instanceof Function // true /a/ instanceof RegExp // true new Date() instanceof Date // true person instanceof People // true
prototype
對象有一個constructor
屬性,默認指向prototype
對象所在的構造函數。因爲constructor
屬性定義在prototype
對象上面,意味着能夠被全部實例對象繼承。所以,正常狀況下,全部對象實例都有一個constructor
屬性,屬性值指向構造此對象實例的構造函數。
[].constructor === Array // true [].constructor === Object // false window.constructor === Window //true
若是不能肯定對象實例的constructor
屬性是什麼函數,可經過函數的name
屬性,從實例獲得構造函數的名稱。
function Foo() {} var f = new Foo(); f.constructor.name // "Foo"
基本數據類型
null
和undefined
是無效的對象,所以是不會有constructor
存在的,這兩種類型的數據須要經過typeof
來判斷。
number
、string
、boolean
三種數據類型有對應的Number
、String
、Boolean
三個原生對象(包裝對象)。所以,也可用 constructor
進行判斷。symbol
類型也可判斷。
(333).constructor.name // "Number" ''.constructor.name // "String" false.constructor.name // "Boolean" Symbol().constructor.name // "Symbol"
引用數據類型
JavaScript 內置對象或是自定義構造函數生成的對象,均可進行判斷。
new Date().constructor === Date //true [].constructor === Array //true function F(){}; var f = new F(); f.constructor === F // true f.constructor === Object // false
constructor
屬性表示原型對象與構造函數之間的關聯關係,有時開發者會因業務關係重寫prototype
,原有的constructor
會丟失,若沒有同時修改constructor
屬性,引用的時候就會出錯,constructor
會默認爲Object
。
function Person(name) { this.name = name; } Person.prototype.constructor === Person // true Person.prototype = { method: function () {} }; Person.prototype.constructor === Person // false Person.prototype.constructor === Object // true
所以,修改原型對象時,通常要同時修改constructor
屬性的指向,或者只在原型對象上添加方法,不要重寫prototype
。
typeoftypeof
可用來判斷基本數據類型和函數,不能夠對引用數據類型進行具體的判斷。
Object.prototype.toString.call(value)Object.prototype.toString.call(value)
可用於判斷多種數據類型:基本數據類型和 JavaScript 內置對象,然而對於一些自定義構造函數生成的對象就不能進行判斷了。
instanceofinstanceof
運算符不適用判斷原始類型的值,只能用於判斷對象,不管是 JavaScript 內置對象或是自定義構造函數生成的對象,均可進行判斷。然而因爲繼承的存在,instanceof
判斷也不徹底準確,只能用來判斷兩個對象是否屬於原型鏈的關係,而不必定能獲取對象的具體類型。
constructorconstructor
屬性可準確的判斷對象實例是由哪一個構造函數生成的,但自定義構造函數生成的對象,每每會由於重寫prototype
形成constructor
屬性指向不許確,所以使用的時候也要注意一下。
Object(x)
的參數爲對象時,老是返回該對象,不作轉換;當參數爲原始類型時,會轉換爲對應的包裝對象的實例,參數爲空或者undefined
或者null
時,返回一個空對象。
function isObject(value) { return value === Object(value); } isObject([]); // true isObject(true); // false
全部數據類型中,只有NaN
不等於它自己
function isNaN(value) { return value !== value; } isNaN(NaN); // true
除了上文提到的三種方法(toString()
、instanceof
、constructor
)可判斷外,還有一個Array
構造函數自帶的方法isArray()
可判斷。
Array.isArray(x)
若是x
是數組,則爲true
; 不然爲false
。
Array.isArray([]); // true Array.isArray(new Array()); // true Array.isArray(Array.prototype); // true 不爲人知的事實:其實 Array.prototype 也是一個數組。
使用以前需檢測一下兼容性,對於不兼容的瀏覽器可以使用下面的代碼建立該方法。
if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; }