JS判断数据类型的方法

108 阅读1分钟

typeof

typeof可以正确输出部分实例的类型字符串

typeof 123 // "number"
typeof '123' // "string"
typeof true  // "boolean"
typeof Symbol(123)  // "symbol"
typeof undefined  // "undefined"
typeof BigInt(1)   // "bigint"
typeof {}  // "object"

但是也有一些问题:

  1. 所有的引用类型都会判断为object,无法进一步判断,除了function
typeof /123$/g // "object"
typeof [] // "object"
typeof new Date() // "object"
typeof function(){}  // "function"
  1. 简单类型null会判断为"object"
typeof null // "object"
  1. 自定义实例无法判断类型,都会输出"object"
function Person(){}
let p1=new Person()
typeof p1 // "object"

instanceof

instanceof用来判断表达式左边的值是否是右边的实例,自定义的构造函数可以使用这个方法来判断,且指向不会随constructor改变而改变

function Person(){}
Person.prototype.constructor= Number
let p1=new Person()
p1 instanceof Person   // true

// instanceof还可以判断继承关系
p1 instanceof Object  // true

但是这个方法也有一些问题:

  1. instanceof对于字面量声明的简单类型值判断有误,引用类型字面量的值可以判断正确
123 instanceof Number // false
new Number(123) instanceof Number // true
// 继承关系
new Number(123) instanceof Object // true

let obj = {}
obj instanceof Object // true
[] instanceof Array // true
// 继承关系
[] instanceof Object // true

function func(){}
func intanceof Function  // true
  1. 不能用来判断null和undefined,因为他们没有构造函数,也不是任何构造函数的实例

constructor

通过访问实例的constructor可以知道这个实例的构造函数

123.constructor  // Number
[].constructor  // Array
/123$/g.constructor  // RegExp
Symbol(1).constructor  // Symbol

但是这个方法也有一些弊端:

  1. 函数的constructor可以手动修改,并不能保证准确
// 动态修改constructor
Object.prototype.constructor=Array;
let obj = {};
obj.constructor;  // Array
  1. 不能用来判断null和undefined,因为他们没有构造函数

toString

这个方法被大部分人推崇为最可靠的判断数据类型的方法

Object.prototype.toString.call(null)   // "[object Null]"
Object.prototype.toString.call(undefined)   // "[object Undefined]"
Object.prototype.toString.call(123)   // "[object Number]"
Object.prototype.toString.call('')   // "[object String]"
Object.prototype.toString.call(true)   // "[object Boolean]"
Object.prototype.toString.call(Symbol(1))   // "[object Symbol]"
Object.prototype.toString.call(BigInt(1))   // "[object BigInt]"
Object.prototype.toString.call({})   // "[object Object]"
Object.prototype.toString.call([])   // "[object Array]"
Object.prototype.toString.call(new Date())   // "[object Date]"
Object.prototype.toString.call(()=>{})   // "[object Function]"

那么这个方法是否真的就这么完美呢,当然不是了,不然其他三个方法怎么混。 toString方法最大的问题就是不能判断自定义构造函数的实例,自定义的实例都会被判断为"[object Object]"

function Person(){}
let p1=new Person()
Object.prototype.toString.call(p1)   // "[object Object]"