JavaScript 的数据类型检测是我们平时开发中经常会遇到的场景,小到基本数据类型大至各种引用数据类型的检测,都是我们需要掌握的知识点。下文会主要讲解 JavaScript 中各种不同数据类型的检测方法以及最后会实现一个数据类型检测的终极方法。
红宝石书告诉我们,JavaScript 中的数据类型有 Undefined
、Null
、Boolean
、Number
、String
、Object
,其中前五种是基本类型,而 Object
是引用类型。实际上,Object
中还包含了其它更为具体的引用类型,如 Array
、Function
、Date
、RegExp
、Error
、Arguments
等。
在本章的叙述中,我都会以上述 12 种数据类型为基础来说明不同的检测方式(实际上 JavaScript 中数据类型不止 12 种,其它数据类型我们鲜少碰到,所以在此就不多做赘述啦)。
我们通常用来检测数据类型的方法,分别是 typeof
和 Object.prototype.toString
,让我们仔细来看看这两个方法。
typeof
MDN 中的叙述是,typeof
操作符返回一个字符串,表示未经计算的操作数的类型。
其使用方式是 typeof operand
或 typeof(operand)
,operand
是一个表达式,表示对象或原始值,其类型将被返回,返回值是表示其数据类型的字符串的小写形式。
那么让我们直接来看一下上述的 12 种数据类型使用 typeof
来检测后返回值分别是什么:
var und=undefined;var nul=null;var boo=true;var num=1;var str='xys'var obj=new Object();var arr=[1,2,3];var fun=function(){}var date=new Date();var reg = /a/g;var err=new Error()var arg;(function getArg(){ arg=arguments;})();console.log(typeof und); // undefinedconsole.log(typeof nul); // objectconsole.log(typeof boo); // booleanconsole.log(typeof num); // numberconsole.log(typeof str); // stringconsole.log(typeof obj); // objectconsole.log(typeof arr); // objectconsole.log(typeof fun); // functionconsole.log(typeof date); // objectconsole.log(typeof reg); // objectconsole.log(typeof err); // objectconsole.log(typeof arg); // object复制代码
可以看到,使用 typeof
方法来检测数据类型,基本类型大部分都能被准确检测并返回正确的字符串(除了 Null
类型,其返回 object
字符串),而引用类型大部分都不能够被准确检测(除了 Function
类型能够准确返回 function
字符串外,其它的都返回了 object
字符串)。
由此可得,typeof
方法并不能够完全精准地检测出上述 JavaScript 中的 12 中数据类型。
Object.prototype.toString
ES5 规范中是这么描述 Object.prototype.toString
的:
可以知道,Object.prototype.toString
最终会返回形式如 [object class]
的字符串,class
指代的是其检测出的数据类型,这个是我们判断数据类型的关键。
同样的,让我们来看下使用 Object.prototype.toString
来检测上述列举到的 12 种数据类型都会返回什么样的结果:
var toString=Object.prototype.toString;console.log(toString.call(und)); // [object Undefined]console.log(toString.call(nul)); // [object Null]console.log(toString.call(boo)); // [object Boolean]console.log(toString.call(num)); // [object Number]console.log(toString.call(str)); // [object String]console.log(toString.call(obj)); // [object Object]console.log(toString.call(arr)); // [object Array]console.log(toString.call(fun)); // [object Function]console.log(toString.call(date)); // [object Date]console.log(toString.call(reg)); // [object RegExp]console.log(toString.call(err)); // [object Error]console.log(toString.call(arg)); // [object Arguments]复制代码
可以看到,Object.prototype.toString
返回的 [object class]
字符串中,class
准确的表示了各个数据的类型,与 typeof
不同的是,class
所代表的数据类型字符串首字母是大写的,而不像 typeof
返回的是小写字符串。
数据类型检测终极方法
通过上述对两个检测数据类型方法的介绍,我们知道 typeof
能够被用来检测除 Null
类型外的其它基本类型,并且能够检测出引用类型中 Function
数据类型,而 Object.prototype.toString
能够检测出所有的数据类型,所以我们可以结合这两个方法来实现一个 JavaScript 数据类型检测的终极方法。
/** * @desc 数据类型检测 * @param obj 待检测的数据 * @return {String} 类型字符串 */function type(obj) { return typeof obj !== "object" ? typeof obj : Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();}复制代码
数据类型的单独检测
有时我们希望直接判断一个数据是否是某个类型,那么我们可以单独实现这些判断某个数据类型的函数,这里直接给出各个函数的实现代码,需要的童鞋可以直接使用。
/** * @desc 是否是 Undefined 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isUndefined(obj) { return obj === void 0;}/** * @desc 是否是 Null 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isNull(obj) { return obj === null;}/** * @desc 是否是 Boolean 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isBoolean(obj) { return typeof(obj) === 'boolean';}/** * @desc 是否是 Number 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isNumber(obj) { return typeof(obj) === 'number';}/** * @desc 是否是 String 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isString(obj) { return typeof(obj) === 'string';}/** * @desc 是否是 Object 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isObject(obj) { return Object.prototype.toString.call(obj) === '[object Object]';}/** * @desc 是否是 Array 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isArray(obj){ return Array.isArray?Array.isArray(obj):Object.prototype.toString.call(obj) === '[object Array]';}/** * @desc 是否是 Function 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isFunction(obj){ return typeof(obj) === 'function';}/** * @desc 是否是 Date 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isDate(obj){ return Object.prototype.toString.call(obj) === '[object Date]';}/** * @desc 是否是 RegExp 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isRegExp(obj){ return Object.prototype.toString.call(obj) === '[object RegExp]';}/** * @desc 是否是 Error 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isError(obj){ return Object.prototype.toString.call(obj) === '[object Error]';}/** * @desc 是否是 Arguments 类型检测 * @param obj 待检测的数据 * @return {Boolean} 布尔值 */function isArguments(obj){ return Object.prototype.toString.call(obj) === '[object Arguments]';}复制代码