typeof
typeof可以正确输出部分实例的类型字符串
typeof 123 // "number"
typeof '123' // "string"
typeof true // "boolean"
typeof Symbol(123) // "symbol"
typeof undefined // "undefined"
typeof BigInt(1) // "bigint"
typeof {} // "object"
但是也有一些问题:
- 所有的引用类型都会判断为object,无法进一步判断,除了function
typeof /123$/g // "object"
typeof [] // "object"
typeof new Date() // "object"
typeof function(){} // "function"
- 简单类型null会判断为"object"
typeof null // "object"
- 自定义实例无法判断类型,都会输出"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
但是这个方法也有一些问题:
- 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
- 不能用来判断null和undefined,因为他们没有构造函数,也不是任何构造函数的实例
constructor
通过访问实例的constructor可以知道这个实例的构造函数
123.constructor // Number
[].constructor // Array
/123$/g.constructor // RegExp
Symbol(1).constructor // Symbol
但是这个方法也有一些弊端:
- 函数的constructor可以手动修改,并不能保证准确
// 动态修改constructor
Object.prototype.constructor=Array;
let obj = {};
obj.constructor; // Array
- 不能用来判断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]"