js的类型判断

95 阅读3分钟

1、使用typeof进行判断

一般使用typeOf判断基础数据类型,如下例子

let str = "123"
let num = 123
let bool = false
let undefin = undefined
let nul = null
let sym = Symbol('123')
let arr = [1, 23]
let obj = {
  a: 1
}

function fn() {}

console.log(typeof (str)) // "string"
console.log(typeof (num)) // "number"
console.log(typeof (bool)) // "boolean"
console.log(typeof (undefin)) // "undefined
console.log(typeof (nul)) // "object"
console.log(typeof (sym)) // "symbol"
console.log(typeof (arr)) // "object"
console.log(typeof (obj)) // "object"
console.log(typeof (fn))  // "function"

从上面的例子可以看出,使用typeof判断null的时候返回的object,这个是js设计时留下的bug,我们记住它就行了。 使用typeOf不能区分对象和数据,他们俩使用typeOf都返回object,接下来我们介绍另外一种数据类型判断条件,它主要是判断是对象是否是new出来的实例。

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

下面是自己实现的instanceof

function myInstanceof(left, right) {
  // 这里先用typeof来判断基础数据类型,如果是,直接返回false
  if(typeof left !== 'object' || left === null) return false;
  // getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
  let proto = Object.getPrototypeOf(left);
  while(true) {                  //循环往下寻找,直到找到相同的原型对象
    if(proto === null) return false;
    if(proto === right.prototype) return true;//找到相同原型对象,返回true
    proto = Object.getPrototypeof(proto);
    }
}
// 验证一下自己实现的myInstanceof是否OK
console.log(myInstanceof(new Number(123), Number));    // true
console.log(myInstanceof(123, Number)); 

以上这两种方法都是有自己的缺陷的:typeof只能判断基础数据类型,并且null由于历史原因也不能准确判断,复杂数据类型除了function其他的不能准确判断;instanceof能判断复杂的数据类型,但是不能判断基础数据类型。

3、使用Object.prototype.toString判断(终极判断)

toString是Object上的原型方法,调用此方法,统一返回 “[object Xxx]” (注意第二个单词首个字母是大写),object队可以直接调用此方法,返回 “[object Object]”,如果其他数据类型调用此方法得使用call调用才能正确返回,至于为啥要抵用call,可自行查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]"

整合以上3中方法,得出下面的的终极判断类型函数

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返回