「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
typeof
typeof一般用来判断一个变量的类型,而能准确判断的一般是基础数据类型。它能够显示判断的类型有:number,string,undefined,booleaan,symbol,bigint,function,object这八种数据类型。同时在判断null数据类型的时候又会出错,给判成了object,而且判断object类型也不能够准确的判断。
那为什么会这样呢,甚至于把基本数据类型null判成object呢?这其实和js的数据存储有很大的关系。js 在底层是怎么存储数据的类型信息呢?或者说,一个 js 的变量,在它的底层实现中,它的类型信息是怎么实现的呢?
其实,js 在底层存储变量的时候,会在变量的机器码的低位 1-3 位存储其类型信息👉
- 000 代表object类型
- 010 代表浮点型
- 100 代表字符串
- 110 代表布尔
- 1 代表整数
但是呢,null和undefined又有点不太一样。
- null 的机器码均为
0 - undefined的机器码为
-2^30来表示
了解到这也就明白了,为什么null会被判为object了,这正是因为其机器码均为0,导致typeof在判断其前三位的机器码时将其直接当成对象来判断了。
关于更多typeof的信息可以参考: MDN上的描述
instanceof
instanceof是JavaScript提供的另一种判断类型的方式,他的使用方式为,左边是需要判断的变量,右边则是一个类型。
上图可得,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。