JavaScript三种方法搞定数据类型检测

avatar
开发工程师 @西安众邦网络科技有限公司

Js的数据类型检测在实际开发项目过程中会经常遇到,这里边存在很多坑,比如我们初学Js的时候可能只知道判断数据类型一个typeof就完事大吉了,其实还有一个instanceof,你以为的这两种就够用了吗?就能准确判断每种数据类型了吗?不会,还有很多坑等着你去跳,今天我们就把这些坑都刨出来给大家看,一起完美避坑!

1. 通过typeof检测

这是我们比较常用的一种类型检测方法,通过一段代码回顾下:

typeof 1            // number
typeof '1'          // string
typeof undefined    // undefined
typeof true         // boolean
typeof Symbol()     // symbol
typeof null         // object
typeof []           // object
typeof {}           // object
typeof console      // object
typeof console.log  // function

通过以上代码可以看出,typeof在判断null之前几个基本数据类型的时候基本上是准确无误的,可是在判断null时返回的是引用类型(object),这明显是有问题,null压根就不是引用类型,这是Js本身的一个bug,还有在判断数组类型、对象以及引用类型上都返回的是object,所以这也是有问题的,只有在判断function类型时是正确的!

以上这些坑在实际开发过程中应尽量避免!

2. 通过instanceof检测

想必 instanceof 的方法你也听说过,我们 new 一个对象,那么这个新对象就是它原型链继承上面的对象了,通过 instanceof 我们能判断这个对象是否是之前那个构造函数生成的对象,这样就基本可以判断出这个新对象的数据类型。下面通过代码来了解一下。

let Car = function() {}
let benz = new Car()
benz instanceof Car // true
let car = new String('Mercedes Benz')
car instanceof String // true
let str = 'Covid-19'
str instanceof String // false

那么typeof与instanceof之间有什么差异呢?

  1. instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型;

  2. 而 typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了 function 类型以外,其他的也无法判断。

总之,不管单独用 typeof 还是 instanceof,都不能满足所有场景的需求,而只能通过二者混写的方式来判断。但是,即使采用两种混写的方式,也只能检测大多数情况,并且写起来也相当难受!

所以,在实际开发中,推荐采用第三种判断方法!

3. 通过Object.prototype.toString检测

toString() 是 Object 的原型方法,调用该方法,可以统一返回格式为 “[object Xxx]” 的字符串,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object];而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息。我们来看一下代码。

Object.prototype.toString({})       // "[object Object]"
Object.prototype.toString.call({})  // 同上结果,加上call也ok
Object.prototype.toString.call(1)    // "[object Number]"
Object.prototype.toString.call('1')  // "[object String]"
Object.prototype.toString.call(true)  // "[object Boolean]"
Object.prototype.toString.call(function(){})  // "[object Function]"
Object.prototype.toString.call(null)   //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/123/g)    //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call([])       //"[object Array]"
Object.prototype.toString.call(document)  //"[object HTMLDocument]"
Object.prototype.toString.call(window)   //"[object Window]"

从上面这段代码可以看出,Object.prototype.toString.call() 可以很好地判断引用类型,甚至可以把 document 和 window 都区分开来。

但是在写判断条件的时候一定要注意,使用这个方法最后返回统一字符串格式为 "[object Xxx]" ,而这里字符串里面的 "Xxx" ,第一个首字母要大写(注意:使用 typeof 返回的是小写),这里需要多加留意。

那么下面来实现一个全局通用的数据类型判断方法,来加深理解,代码如下。

function getType(obj){
  let type  = typeof obj;
  if (type !== "object") {    // 先进行typeof判断,如果是基础数据类型,直接返回
    return type;
  }

  // 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
  return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');  // 注意正则中间有个空格
}

/* 代码验证,需要注意大小写,哪些是typeof判断,哪些是toString判断?思考下 */
getType([])     // "Array" typeof []是object,因此toString返回
getType('123')  // "string" typeof 直接返回
getType(window) // "Window" toString返回
getType(null)   // "Null"首字母大写,typeof null是object,需toString来判断
getType(undefined)   // "undefined" typeof 直接返回
getType()            // "undefined" typeof 直接返回
getType(function(){}) // "function" typeof能判断,因此首字母小写
getType(/123/g)      //"RegExp" toString返回

以上就是Js中检测数据的三种方法,最后实现了一个通用类检测方法,基本上可以搞定所有数据类型的检测,每一种方法都有自己的强项和不足,我们在使用过程中,还是要看业务场景具体选择!

欢迎大家点赞关注交流,给大家推荐个我们开源的优秀的开源公众号/小程序商城系统,欢迎Star,使用交流! 开源项目传送门:github.crmeb.net/u/xingfu