类型判断在 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