Fork me on GitHub

javascript类型检测汇总

汇总一些关于javascript中的类型检测的问题

刚进入博客园不长时间,整理一些简单的易懂的东西出来分享一下。

Javascript中的数据类型

说到类型检测前我们首先需要确定javascript中一共有多少种数据类型。

  • javascript不支持任何自定义类型的机制,而所有的值最终都将是6大类型之一。由于javascript数据类型具有动态性,因此的确没有再定义其他数据类型的必要。

  • javascript数据类型总的分为两大类:基本数据类型(5种),一种引用数据类型,共 6种,如下:

    i. 基本数据类型

    1. Undefined 类型
    2. Null 类型
    3. Boolean 类型
    4. Number 类型
    5. String 类型

    ii.引用数据类型

    1. Object 类型
  • 检测数据类型的方法有: typeofinstanceofconstructorprototype。当然还有很多关于第三那方库的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方法,所以需要以callapply的形式来配合使用才最安全,不说了看栗子:

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

posted @ 2018-02-06 14:45  AaronShen  阅读(171)  评论(0编辑  收藏  举报