彻底搞懂JS数据类型判断

811 阅读3分钟

前言

首先我们要搞懂JS的数据类型有哪些,ES6之前JS的数据类型有6种,在ES6(包括ES6)之后新增了两种数据类型 Symbol(ES6)Bigint(ES10)

JS的数据类型:undefined、null、boolean、string、number、object、symbol、bigint

基本数据类型:undefined、null、boolean、string、number、symbol、bigint

引用数据类型:object、function、array、Date、RegExp、Set、Map

判断数据类型方法

  • typeof
  • instanceof
  • Constructor
  • Object.prototype.toString.call()

typeof

typeof 能判断出 undefined、boolean、number、string、object、function、symbol、bigint, 它常用于判断基本数据类型。

typeof能判断所有的基本数据类型吗?

不能,他不能判断 null。typeof null 为 object

在开始之前,先声明常见的数据类型

const num = 1			// number 
const str = '123'		// string
const bol = false		// boolean
const fun = function() {}	// function
const obj = {}			// object
const arr = []			// array
const sym = Symbol()		// symbol
const bint = 10n		// bigint
const und = void(0)	        // undefined
const nul = null		// null
const dat = new Date()		// date
const rep = /12/g		// regexp
const set = new Set()		// set
const map = new Map()		// map

现在我们来测试一下

typeof num		// number
typeof str		// string
typeof bol		// boolean
typeof fun		// function
typeof obj		// object
typeof arr		// object
typeof sym		// symbol
typeof bint		// bigint
typeof und		// undefined
typeof nul		// object
typeof dat		// object
typeof rep		// object
typeof set		// object
typeof map		// object

instanceof

instanceof用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上

object instanceof constructor

object      某个实例对象
constructor 某个构造函数

我们来看下使用场景

function Cat() {}
function Dog() {}

const c = new Cat()

c instanceof Cat	// true, 因为c的隐式原型 == Cat.prototype

c instanceof Dog	// false, 因为Dog.prototype不在c的原型链上

c instanceof Object	// true 因为Object在c的原型链上

instanceof判断右边的原型是否在左边的原型链上,根据这个思路我们来手写一下myInstanceof

const myInstanceof = (left, right) => {
  let lp = left.__proto__
  while(lp) {
    if(lp === right.prototype) return true
    lp = lp.__proto__
  }
  return false
}

这样我们就能实现基础功能,但是还有两个问题

  • 在判断myInstanceof(1, Number)true,我们使用a instance Numberfalse

  • 在判断myInstanceof(Cat, Object)false,使用Cat instanceof Objecttrue

为了解决这两个问题,代码修改如下

const myInstanceof = (left, right) => {
  if(typeof left !== 'object' && typeof left !== 'function') return false
  let lp = left.__proto__
  while(lp) {
    if(lp === right.prototype) return true
    lp = lp.__proto__
  }
  return false
}

这样就解决了上面的两个问题

Construtor

Constuctor能判断出大多数的数据类型,但是不能判断出undefined和null,因为他俩没有constructor

num.constructor.toString())     // function Number(){[native code]}
str.constructor.toString())     // function String(){[native code]}
bol.constructor.toString())     // function Boolean(){[native code]}
fun.constructor.toString())     // function Function(){[native code]}
obj.constructor.toString())     // function Object(){[native code]}
arr.constructor.toString())     // function Array(){[native code]}
sym.constructor.toString())     // function Symbol(){[native code]}
bint.constructor.toString())    // function Bigint(){[native code]}
und.constructor.toString())     // Cannot read properties of undefined (reading 'constructor')
nul.constructor.toString())     // Cannot read properties of null (reading 'constructor')
dat.constructor.toString())     // function Date(){[native code]}
rep.constructor.toString())     // function RegExp(){[native code]}
set.constructor.toString())     // function Set(){[native code]}
map.constructor.toString())     // function Map(){[native code]}

Object.prototype.toString.call()

Object.prototype.toString.call()能判断出所有的类型,全能选手。

Object.prototype.toString.call(num))		// [object Number]
Object.prototype.toString.call(bol))		// [object Boolean]
Object.prototype.toString.call(str))		// [object String]
Object.prototype.toString.call(fun))		// [object Function]
Object.prototype.toString.call(obj))		// [object Object]
Object.prototype.toString.call(arr))		// [object Array]
Object.prototype.toString.call(sym))		// [object Symbol]
Object.prototype.toString.call(bint))		// [object Bigint]
Object.prototype.toString.call(und))		// [object Undefined]
Object.prototype.toString.call(nul))		// [object Null]
Object.prototype.toString.call(dat))		// [object Date]
Object.prototype.toString.call(rep))		// [object Regexp]
Object.prototype.toString.call(set))		// [object Set]
Object.prototype.toString.call(map))		// [object Map]
Object.prototype.toString.call(new WeakMap))	// [object WeakMap]

我们可以用slice方法就可以把类型提取出来了

function getType(el) {
  return Object.prototype.toString.call(el).slice(8, -1).toLowerCase()
}

结语

现在对数据类型和数据类型判断大概有了清晰的知识结构,如果有问题,欢迎小伙伴们指正🥳