typeof、instanceof、Object.prototype.toString.call( )

123 阅读3分钟

数据类型

  • 在ES5的时候,我们知晓的数据类型有6种:NumberStringBooleanundefinedobjectNull
  • ES6 中新增了一种 Symbol 。这种类型的对象永不相等,即使创建的时候传入相同的值,可以解决属性名冲突的问题,做为标记。
  • 谷歌67版本中还出现了一种 bigInt。是指安全存储、操作大整数。

按照数据存储方式分为基本数据类型(原始类型)和引用数据类型(对象类型)可查看

  • 内存空间又被分为两种,栈内存与堆内存。
  • JavaScript中的原始类型的值被直接存储在栈中,在变量定义时,栈就为其分配好了内存空间,由于栈中的内存空间的大小是固定的,那么注定了存储在栈中的变量就是不可变的。
  • 相对于上面具有不可变性的原始类型,我习惯把对象称为引用类型,引用类型的值实际存储在堆内存中,它在栈中只存储了一个固定长度的地址,这个地址指向堆内存中的值。

基本数据类型: StringNumberBooleanNullUndefinedSymbol

引用数据类型: Object【Object是个大类,function函数、array数组、date日期...JavaScript的内置函数等都归属于Object】

typeof

typeof 可以用于判断一个变量的类型,我们可以使用 typeof 来判断number, string, object, boolean, function, undefined, symbol 这七种数据类型,可以使用typeof用于判断基本类型,点击查看MDN文档

image.png 但是object类型不能具体细分其包含的数据类型(对象,数组,Set类型,Map类型),并且Null类型也会被判断为"object"。

instanceof

instanceof 主要的作用就是判断一个实例是否属于某种类型,instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。参考文章

function Foo() {
}

Object instanceof Object // true
Function instanceof Function // true
Function instanceof Object // true
Foo instanceof Foo // false
Foo instanceof Object // true
Foo instanceof Function // true

原型链:

5c9eae049361091b043b42bc7528c25.jpg

Object.prototype.toString.call( )

还有一个不错的判断类型的方法,就是Object.prototype.toString,我们可以利用这个方法来对一个变量的类型来进行比较准确的判断。

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]"

封装函数

为了更方便的使用,我们封装一个函数:

function getType(value) {
    let type = typeof value;
    if (type !== 'object') { // 如果是原始数据类型,直接返回
        return type;
    }
    // 如果是引用数据类型,再进一步判断,正则返回结果
    return Object.prototype.toString.call(value).replace(/^\[object (\S+)\]$/, '$1');
}

getType(123); // number
getType('xxx'); // string
getType(() => {}); // function
getType([]); // Array
getType({}); // Object
getType(null); // Null

总结

简单来说,我们使用 typeof 来判断基本数据类型是没问题的,需要注意的是当用 typeof 来判断 null 类型为object的问题。如果想要判断一个对象的具体类型可以考虑用 instanceof,但是 instanceof 也可能判断不准确,比如一个数组(可以用 Array.isArray(value) 用来判断数组),他可以被 instanceof 判断为 Object。所以我们要想比较准确的判断对象实例的类型时,可以采取 Object.prototype.toString.call 方法。