从入门到放弃?一篇搞定 JS 所有类型判断

32 阅读4分钟

引言

  不少前端小伙伴写 JS 时总被数据类型坑:null被 typeof 错判成对象、数组识别为 Object,原生数值用 instanceof 判断屡屡出错,面试还总被深挖底层原理。本文细数 JS 全部数据类型,详解三种常用校验方式的优缺点与底层逻辑,搭配实操案例帮你按需选型,轻松避开类型判断各类 bug。

1. JS有哪些类型

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

  引用类型:function、 array、 object、 date

  想了解更多数据类型的知识点,可以看我往期的文章: 前端基础必看|JS数据类型全家桶

2. typeof 方法

内容:

  1. 可以准确的判断除了 null 之外的所有的原始类型
  2. 所有的引用类型在 typeof 眼里都是 object,除了函数

  关于 typeof 方法的使用,用一段代码和你讲清楚:

let num = 123
let n = null
let u = undefined
let s = '12112'
let b = false
let sy = Symbol(1)
let bint = 123456n

let arr = []
let obj = {}
let fn = function(){}
console.log('number:' + typeof num)
console.log('null:' + typeof n)    //object
console.log('undefined:' + typeof u)
console.log('string:' + typeof s)
console.log('boolean:' + typeof b)
console.log('symbol:' + typeof sy)
console.log('bigint:' + typeof bint)

console.log('object:' + typeof obj)
console.log('array:' + typeof arr)    //object
console.log('function:' + typeof fn)   

运行结果如下:

image.png

  运行结果中,有两个类型的判断并不符合预期:nullarray 都会被识别为 object。很多人都会对此感到疑惑,这究竟是为什么呢?想要弄清楚背后的原因,我们必须先了解 typeof 的底层执行原理:typeof 是通过将数据转换为二进制来判断类型的。在二进制判断规则中,只要数据的二进制前三位均为 0 ,就会被判定为引用类型;而所有引用类型转换为二进制后,前三位都是 0(函数除外),null 对应的二进制则是全 0。

3. instanceof 方法

内容:

  1. 只能判断引用类型,无法判断原始类型
  2. 它是通过隐式原型链来查找 x 是否隶属于 X 这个类型

  接下来我们通过实际代码,直观演示 instanceof 方法的具体使用:

let num = 123
let n = null
let u = undefined
let s = 'new123'
let b = false
let sy = Symbol(1)
let bint = 123456n

let arr = []
let obj = {}
let fn = function(){}

console.log(arr instanceof Array)     //true
console.log(arr instanceof Object)     //true

console.log(obj instanceof Object)    //true
console.log(fn instanceof Function)   //true
console.log(s instanceof String)      //false
console.log(num instanceof Number)    //false
console.log(b instanceof Boolean)     //false

console.log(bint instanceof BigInt);  //false
console.log(sy instanceof Symbol);    //false

运行结果如下:

image.png

  不难发现,instanceof 仅适用于引用类型校验。那它又是依托隐式原型链,如何判断实例 x 是否归属于构造函数 X?下面结合源码拆解说明:

function myInstanceof(l, r) {
  if (typeof l !== 'object' && typeof l !== 'function' || l == null) {
    return false
  }
  while(l !== null) {
    if (l.__proto__ === r.prototype) {
      return true
    }
    l = l.__proto__
  }
}
  1. 基础类型直接不匹配:string/number/boolean 等基础类型没有原型链,直接返回 false

  2. 沿原型链向上查找:通过对象的 __proto__ 逐层往上遍历原型链;

  3. 匹配规则:如果某一层原型 === 构造函数的 prototype,则返回 true

  4. 查找到顶端结束:遍历到原型链终点 null 仍未匹配,返回 false

4.Object.prototype.toString.call() 方法

  Object.prototype.toString.call() 是 JavaScript 中最精准、最通用的类型判断方法,能完美区分所有数据类型

  在聊 Object.prototype.toString.call() 方法前我们先了解一下什么是Object.prototype.toString() 方法。

官方介绍是这样的:

image.png

可能有点懵,我来给你解释一下:

  1. 如果 this 值为 undefined,则返回 "[object Undefined]"。
  2. 如果此值为 null,则返回 "[object Null]"。
  3. 令 O 为调用 ToObject 并将 this 值作为参数传递所得到的结果。 // const O = ToObject(this)
    // O 永远都是 Object
  4. 令class为O的[[Class]]内部属性的值。 // const class = O.[[calss]]
  5. 返回将三个字符串 "[object "、class 和 "]" 拼接后得到的字符串值。

  所以Object.prototype.toString()方法是不能完成类型判断的,无论什么类型传进去都是Object。

  Object.prototype.toString 是 JS 底层用于获取数据原生类型的方法,但它仅依赖 this 指向识别类型,直接调用时 thisObject.prototype,只能得到 [object Object]Object.prototype.toString.call() 则通过 call 强行修改 this 为待检测的值,让方法读取该值的真实内置类型,成为 JS 中最通用、最精准的类型判断方式。

  通过示例代码演示 Object.prototype.toString.call() 的使用逻辑:

let s = 'hello'
let num = 123
let f = true
let u = undefined
let n = null
let sy = Symbol(1)
let big = 12343242n

let arr = []
let obj = {}
let fn = function(){}

console.log(Object.prototype.toString.call(s));
console.log(Object.prototype.toString.call(num));
console.log(Object.prototype.toString.call(arr).slice(8, -1));
console.log(Object.prototype.toString.call(fn).slice(8, -1)); // '[object Function]'

运行结果如下:

image.png

扩展知识 Array.isArray()

  JS 专门给数组准备了快捷判断的方法Array.isArray(),想查是不是数组直接丢参数就行,写法简单好用;但它只管数组,别的数据类型识别不了,查数字、日期、null 还得靠Object.prototype.toString.call()

5.总结

  • typeof 是 “快餐”:快但不精准,适合原始类型(除 null)和函数的快速判断;
  • instanceof 是 “族谱查档”:只认引用类型,靠原型链判断,适合自定义类的继承判断
  • Object.prototype.toString。call() 是 “CT 扫描”:精准识别所有类型,通用场景首选;
  • Array.isArray() 是 “数组专属 VIP”:判断数组比instanceof 靠谱 10 倍。

记住这些,以后写类型判断再也不会被面试官问倒,也不会在开发中踩各种奇葩坑了!💪