一文教会你js中常见的类型判断

145 阅读2分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

typeof

typeof一般用来判断一个变量的类型,而能准确判断的一般是基础数据类型。它能够显示判断的类型有:numberstringundefinedbooleaansymbolbigintfunctionobject这八种数据类型。同时在判断null数据类型的时候又会出错,给判成了object,而且判断object类型也不能够准确的判断。

1.png

那为什么会这样呢,甚至于把基本数据类型null判成object呢?这其实和js的数据存储有很大的关系。js 在底层是怎么存储数据的类型信息呢?或者说,一个 js 的变量,在它的底层实现中,它的类型信息是怎么实现的呢?

其实,js 在底层存储变量的时候,会在变量的机器码的低位 1-3 位存储其类型信息👉

  • 000 代表object类型
  • 010 代表浮点型
  • 100 代表字符串
  • 110 代表布尔
  • 1 代表整数

但是呢,null和undefined又有点不太一样。

  1. null 的机器码均为0
  2. undefined的机器码为-2^30来表示

了解到这也就明白了,为什么null会被判为object了,这正是因为其机器码均为0,导致typeof在判断其前三位的机器码时将其直接当成对象来判断了。

关于更多typeof的信息可以参考: MDN上的描述

instanceof

instanceof是JavaScript提供的另一种判断类型的方式,他的使用方式为,左边是需要判断的变量,右边则是一个类型。

2.png

上图可得,instanceof可以判断出来一个变量当前的类型,也可以判断出他的祖先类型。

其实instanceof的原理就是判断左边的实例的原型链上是否包含了右边的变量的prototype,如果右边的类型存在左边的原型链上,返回true,否则就返回false,因此可以简单实现一个instanceof:

function myInstanceof (left,right){
    if(arguments.length < 2) throw('error!!!')
    let rightProto = right.prototype
    let leftValue = left.__proto__
    while(true){
        if(leftValue === null) return false
        if(leftValue === rightProto) return true
        leftValue = leftValue.__proto__
    }
}

let str = new String('123')
console.log(myInstanceof(str,String))
console.log(myInstanceof(str,Number))
console.log(myInstanceof(str,Object))

正因为instanceof基于原型链来判断类型,所以也会出现一些很有意思的现象:

Function instanceof Function // true
Object instanceof Object // true

Object 的 prototype 属性是 Object.prototype, 而由于 Object 本身是一个函数,由 Function 所创建,所以 Object.__proto__ 的值是 Function.prototype,而 Function.prototype 的 __proto__ 属性是 Object.prototype,所以我们可以判断出,Object instanceof Object 的结果是 true。

Object.prototype.toString.call

通过Object.prototype.toString.call我们可以判断大部分的数据类型

Object.prototype.toString.call(1) // "[object Number]"

Object.prototype.toString.call('hi') // "[object String]"

Object.prototype.toString.call({a:'hi'}) // "[object Object]"

Object.prototype.toString.call([1,'a']) // "[object Array]"

Object.prototype.toString.call(true) // "[object Boolean]"

Object.prototype.toString.call(() => {}) // "[object Function]"

Object.prototype.toString.call(null) // "[object Null]"

Object.prototype.toString.call(undefined) // "[object Undefined]"

Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"

总结

一般可以用typeof来判断基础数据类型,但是要注意不能用它来判断null,当想判断一个实例是不是某种类型时,可以使用instanceof,当想准确判断某一类型,还是推荐使用Object.prototype.toString.call