汇总一些关于javascript中的类型检测的问题
刚进入博客园不长时间,整理一些简单的易懂的东西出来分享一下。
Javascript中的数据类型
说到类型检测前我们首先需要确定javascript中一共有多少种数据类型。
- javascript不支持任何自定义类型的机制,而所有的值最终都将是6大类型之一。由于javascript数据类型具有动态性,因此的确没有再定义其他数据类型的必要。
javascript数据类型总的分为两大类:基本数据类型(
5
种),一种引用数据类型,共6
种,如下:i. 基本数据类型
Undefined
类型Null
类型Boolean
类型Number
类型String
类型
Object
类型
检测数据类型的方法有:
typeof
、instanceof
、constructor
、prototype
。当然还有很多关于第三那方库的API方法我们就不一一列举了。
利用typeof进行类型检测
首先我们使用typeof
来将我们常用的这几种类型分别测试一下看看返回的是什么
typeof undefined
//"undefined"
typeof null
//"object"
typeof true
//"boolean"
typeof 123
//"number"
typeof 'aaa'
//"string"
typeof {a : 1}
//"object"
下图是我们在chrome
开发者工具中打印的结果,做一下对比
首先我们看到了第一个问题那就是null和对象同时都检测到是"object"
这种类型,其实null不是一个空引用(有很多人认为null就是一个空引用), 而是一个原始值。
啰嗦一下: 其实这是一个js原生的bug,早在ES6版本的提案中就有人曾提到应该修复这个bug,但是被驳回了,原因是历史遗留的代码太多,喜欢的可以去看一下: 地址。
当然了,即使是bug那我们也得避免,其实方法很简单也很多,下面举一个简单的例子:
let a = {a : 1};
if(typeof a === 'object') {
a !== null ? 'object' : 'null';
}
好了, 除了null视乎都很正常,但是我们可以再深入一下看看我们常用的类型是否都能检测的出来:
typeof [1,2,3]
//"object"
typeof new Date()
//"object"
typeof new RegExp(\^\W+$\)
//"object"
ヾ(。`Д´。)什么情况???
其实呢typeof
用于判断基本数据类型没有问题,但是判断引用数据类型时,就心有余而力不足了。
既然这样那我们就去试试第二种方法,接着往下看
利用instanceof进行类型检测
我们用instanceof
判断一下上面遗留下来的那几个问题[1,2,3] ,new Date(), new RegExp(\^\W+$\)
,分别是Date,数组,正则:
[1,2,3] instanceof Array
//true
new Date() instanceof Date
//true
new RegExp('\W+') instanceof RegExp
//true
看到这要是觉得事情仿佛都解决了,那你就高兴的太早了
如果我们需要判断一个未知的变量是什么类型用instanceof
怎么实现?
//假设一个未知的变量类型为数组
var unknown = [1,2,3]
//我们只能通过繁琐的对比最后才能准确的定位到这是个Array
if(unknown instanceof Array) {
alert('Array');
}else if(unknown instanceof Date) {
alert('Date');
}....
上面的代码显然不是我们想要的结果,总的来说instanceof
只适用于校验变量是否是某一种类型,对于校验未知类型的变量并不是很适用。
你可能会问那就没有其他的方法了吗?
接着往下看
利用constructor进行类型检测
上面我们留下了instanceof
对未知类型检验的问题,感觉instanceof
不够灵活,那我们接着说另一种方法
[1,2,3].constructor
//ƒ Array() { [native code] }
[1,2,3].constructor === Array
//true
(new Date()).constructor
//ƒ Date() { [native code] }
(new Date()).constructor === Date
//true
通过constructor
方法我们能对未知的类型进行鉴定,O(∩_∩)O,然而有时候结果总是出人意料的,假设是这种情况呢?
function Fun(){};
Fun.prototype = new Array();
let fun = new Fun();
fun.constructor === Fun
//false;
fun.constructor === Array
//true;
在chrome
控制台将测试的结果输出
O__O" 看来利用constructor
去做类型检测还是有点缺陷,当出现原型继承的情况,constructor
得到的结果就是错误的。
看到这你可能会说, 赶紧说其他的方法。
OK 办法总比困难多,新的方法出现了,往下看:
利用Object.prototype.toString.call进行类型检测
javascript中Object
有个toString
方法,该方法返回一个表示该对象的字符串 , 但是很多对象(如:Array等)都重写了toString
方法,所以需要以call
或apply
的形式来配合使用才最安全,不说了看栗子:
Object.prototype.toString.call(null);
//”[object Null]”
Object.prototype.toString.call(undefined);
//”[object Undefined]”
Object.prototype.toString.call('aaa');
//”[object String]”
Object.prototype.toString.call(123);
//”[object Number]”
Object.prototype.toString.call(true);
//”[object Boolean]”
Object.prototype.toString.call([1,2,3]);
//"[object Array]"
Object.prototype.toString.call({a : 1});
//"[object Object]"
Object.prototype.toString.call(new Date());
//"[object Date]"
Object.prototype.toString.call(function(){});
//"[object Function]"
我们将chrome
控制台输出的截图抬上来看看
上面的例子很容易说明Object.prototype.toString.call()
是一个不错的基本数据类型和引用数据类型的一个方式。其实像jQuery
中$.type()
也是配合这种方式去实现的,最后我们将其源码拿过来瞅两眼
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),function( i, name ) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );
function toType( obj ) {
if ( obj == null ) {
return obj + "";
}
// Support: Android <=2.3 only (functionish RegExp)
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call( obj ) ] || "object" :
typeof obj;
}
简单说说: 假设我们传进去一个数组[1,2,3]
,路线如下:class2type
为全局变量,键为"[object Array]"
这种形式保存,而它的值则为小写的array
。
toType
接受到的形参首先判断其是否为null,如果是直接return 字符串类型null
,至此null
被过滤。
紧接着判断是否为object
或者function
类型,如果是任意一种那便使用我商厦管所说的Object.prototype.toString.call()
进行判断,判断出的结果对应class2type
对象中的键并找出对应的值将其返回,至此复杂类型数据被过滤。
最后如果不是复杂类型直接使用后typeof
进行判断返回。
说了这么多 ,也该总结一下了
typeof
用来判断基本类型,而在引用类型方面显得无力。instanceof
用来判断引用类型的具体类型,但不够灵活。constructor
用来判断实例的构造函数,但容易被伪造。Object.prototype.toString.call()
用来获取对象的描述字符串。
文章写的有点烂,有什么问题或者建议大家可以通过留言或者邮箱的方式告诉我。多谢O(∩_∩)O