類型判斷在 web 開發中較爲常見,簡單的有判斷數字仍是字符串,判斷是數組仍是對象稍微複雜一些,再複雜一點的有判斷日期、正則、錯誤類型,再再複雜一點還有好比判斷 plainObject、空對象、Window 對象等等。javascript
經過本文,我將嘗試概述Javascript中類型判斷的幾種方法(基於ES5的規範)。java
typeof判斷類型方法算是咱們最最經常使用的了,直接上代碼:git
typeof 3 // "number"
typeof "abc" // "string"
typeof {} // "object"
typeof true // "boolean"
typeof undefined // "undefined"
typeof function(){} // "function"
複製代碼
以上這些類型都比較正常,直到:github
typeof null // "object"
複製代碼
這顯然是一個錯誤。 這可能會在之後的ECMAScript哪一個版本中修復,返回值將爲「null
」。web
除此以外 Object
下還有不少細分的類型,好比 Array
、Date
、RegExp
、Error
等。若是用 typeof
去檢測這些類型,舉其中幾個例子:數組
var array1 = []
var array2 = new Array();
var date = new Date();
var error = new Error();
console.log(typeof array1); // object
console.log(typeof array2); // object
console.log(typeof date); // object
console.log(typeof error); // object
複製代碼
所以,typeof
很是善於區分不一樣類型的原始值,並區分它們和對象,但在區分不一樣類型的對象(包括數組和null
)時徹底沒用,那這該怎麼區分?有沒有更好的解決方法呢?函數
JS做爲一門越發成熟的語言,解決方法固然有!嘿嘿~這就是Object.prototype.toString
!ui
那 Object.prototype.toString
看起來是一長串字母,看起來比較複雜誒~爲了講清楚,在toString方法被調用時,是會執行下面的操做步驟的:this
this
的值爲undefined
,則返回"[object Undefined
]".null
,則返回"[object Null
]".ToObject(this)
的結果.[[Class]]
的值."[object "
和 class
和 "]"
三個部分組成的字符串.經過規範,咱們至少了解了調用 Object.prototype.toString
最終會返回一個由 "[object "
和 class
和 "]"
組成的字符串,而 class
是要判斷的對象的內部屬性。spa
看這些規範仍是隻知其一;不知其二的狀態吧,直接上代碼直觀一點:
console.log(Object.prototype.toString.call(3)) // [object Number]
console.log(Object.prototype.toString.call([1, 2, 3])) // [object Array]
console.log(Object.prototype.toString.call({})) // [object Object]
console.log(Object.prototype.toString.call(null)) // [object Null]
var date = new Date();
console.log(Object.prototype.toString.call(date)) // [object Date]
複製代碼
咱們能夠看到這個 class 值其實就是識別對象類型的關鍵!
所以咱們能夠用 Object.prototype.toString
方法識別出更多類型!那到底能識別多少種類型呢?那仍是看代碼數個數吧~嘿嘿
var number = 1; // [object Number]
var string = '123'; // [object String]
var bool = true; // [object Boolean]
var unde = undefined; // [object Undefined]
var nul = null; // [object Null]
var obj = {} // [object Object]
var array = []; // [object Array]
var date = new Date(); // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g; // [object RegExp]
var func = function a(){}; // [object Function]
function checkTypes() {
for (var i = 0; i < arguments.length; i++) {
console.log(Object.prototype.toString.call(arguments[i]))
}
}
checkTypes(number, string, bool, unde, nul, obj, array, date, error, reg, func)
//打印出
[object Number]
[object String]
[object Boolean]
[object Undefined]
[object Null]
[object Object]
[object Array]
[object Date]
[object Error]
[object RegExp]
[object Function]
複製代碼
除了以上 11 種以外,還有3種:
console.log(Object.prototype.toString.call(Math)); // [object Math]
console.log(Object.prototype.toString.call(JSON)); // [object JSON]
function a() {
console.log(Object.prototype.toString.call(arguments));
}
a(); // [object Arguments]
複製代碼
這裏看咱們至少能夠識別14 種類型,而[[class]] 屬性數量至少有 12 個。
利用Object.prototype.toString
判斷類型的方法來寫個類庫吧,此類庫來自(Axis.js)[//github.com/toddmotto/axis]:
(function (root, factory) {
// 判斷是否使用了模塊
if (typeof define === 'function' && define.amd) {
// 使用AMD模塊
define(factory);
} else if (typeof exports === 'object') {
// 使用CMD模塊
module.exports = factory;
} else {
// 沒有使用模塊,放在全局下
root.axis = factory();
}
})(this, function () {
// 嚴格模式
'use strict';
var exports = {};
// 將字符串轉爲數組
var types = 'Array Object String Date RegExp Function Boolean Number Null Undefined'.split(' ');
// 判斷類型
var type = function () {
return Object.prototype.toString.call(this).slice(8, -1);
};
// 遍歷types,爲exports對象添加isArray、isObject...等方法
for (var i = types.length; i--;) {
exports['is' + types[i]] = (function (self) {
return function (elem) {
// type.call(elem)將type方法裏的this指針指向elem
return type.call(elem) === self;
};
})(types[i]);
}
return exports;
});
複製代碼
使用方法也比較簡單,直接上代碼:
axis.isArray([]); // true
axis.isObject({}); // true
axis.isString(''); // true
axis.isDate(new Date()); // true
axis.isRegExp(/test/i); // true
axis.isFunction(function () {}); // true
axis.isBoolean(true); // true
axis.isNumber(1); // true
axis.isNull(null); // true
axis.isUndefined(); // true
複製代碼
考慮到實際狀況下並不會檢測 Math
和 JSON
,並且上面這種方法也檢測不了這兩種類型,因此去掉這兩個類型的檢測。同時也不能識別自定義對象類型。
當 typeof
也有無解的時候,那麼咱們是否還有其餘好的方法來判斷一個變量是自定義對象類型呢?
咱們知道,javascript 的全部對象都有一個 constructor
屬性,這個屬性能夠幫咱們判斷 object 數據類型,直接上代碼:
//alert(1.constructor); //報錯 數字常量無 constructor 屬性
var num = 1;
console.log(num.constructor == Number); //true
console.log("miqilin".constructor == String); //true
var str = "miqilin";
console.log(str.constructor == String); //true
var obj= null;
console.log(obj.constructor); //報錯,null 沒有 constructor 屬性
var none = undefined;
console.log(obj.constructor); //報錯,undefined 沒有 constructor 屬性
複製代碼
能夠看出,數字型常量,null
和 undefined
都沒有 constructor
屬性。
以前覺得到這就所有分析完了,看了多篇外文才知道原來還有可挖掘的東西,來看下面的代碼:
function Animal() {
}
function Cat() {
}
Cat.prototype = new Animal();
Cat.prototype.CatchMouse = function () {
//do some thing
}
var obj = new Cat();
console.log(obj.constructor == Cat); //false ??由於 Cat.prototype不在obj的原型鏈上
console.log(obj.constructor == Animal); //true 理解
複製代碼
原來對於原型鏈繼承的狀況,constuctor
也不怎麼好用了。那怎麼辦呢?
嘿嘿~原來還有一種方法能夠解決這種困境,那就是 instanceof
。instanceof
運算符會告訴您對象是不是某種類型的實例, 這裏所謂的「類型」其實就是構造函數。直接上代碼:
function Animal() {
}
function Cat() {
}
Cat.prototype = new Animal();
Cat.prototype.CatchMouse = function () {
//do some thing
}
var obj = new Cat();
console.log(obj instanceof Cat); //true 毫無疑問
console.log(obj instanceof Animal); //true 能夠理解
複製代碼
instanceof
適用於全部原生類型:
[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
複製代碼
因此這裏constructor
又有點優點了,能夠適用於原始類型number
,string
和boolean
的判斷(constructor
小節有例子)。
雖然檢查任何一種特定類型真的不是那麼難,但你可能不得不在此過程當中作出不少選擇,勢必會引發一些混亂。所以,瞭解全部不一樣的選項會有所幫助,如下是對四種方法可識別類型的簡單歸納:
typeof:
Null
除外)Function
除外)Object.prototype.toString:
Object
, Date
, Array
)constructor:
Undefined
/Null
除外)instanceof:
類型轉換的圖形化表示(其中紅色單元格表示該判斷方式不支持的類型):
還有更復雜的判斷好比 plainObject
、空對象、Window
對象、類數組對象等,還未涉及,後續也會增長。 敬請關注!
本人Github連接以下,歡迎各位Star