1. instanceof
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上。语法
object instanceof constructor
参数
object
某个实例对象
constructor
某个构造函数
从它的语法上就能看出,它是根据 构造器函数 来判断类型的,且它只支持 对象 的判断
也就是说它无法判断以下情况
let number = 123
let string = '123'
let bool = true
console.log(number instanceof Number) // false
console.log(string instanceof String) // false
console.log(bool instanceof Boolean) // false
原因就如它的判断规则所说,它是“根据 构造器函数 来判断类型的,且它只支持 对象 的判断”这三个变量被初始化为了原始值,而不是对象,因此没有 [[Prototype]] 。
除此之外仍然有易错的情况。
console.log(Number(123) instanceof Number) // false
console.log(String('123') instanceof String) // false
console.log(Boolean(true) instanceof Boolean) // false
原因也基本相同,Number(123),这样没有使用new关键字的使用方式,其实是将参数进行“强制转换”,而使用new关键字则是包装一个对象。
console.log(new Number(123) instanceof Number) // true
console.log(new String('123') instanceof String) // true
console.log(new Boolean(true) instanceof Boolean) // true
所以new关键字相当于做了这样一件事:
new String('123') === Object(String('123'))
总结:instanceof不能直接对一些直接赋值的基本类型进行判断,除此之外,也一样无法判断null、undefined,因为它相当于判断某某某是否为某某对象的实例,所以instanceof的右边无法写null或者undefined,会报错TypeError: Right-hand side of 'instanceof' is not an object
2. typeof
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
语法
typeof 运算符后接操作数:
typeof operand typeof(operand)参数
operand
一个表示对象或原始值的表达式,其类型将被返回。
类型 | 结果 |
---|---|
Undefined | “undefined” |
Null | “object” |
Boolean | “boolean” |
Number | “number” |
BigInt(ECMAScript 2020 新增) | “bigint” |
String | “string” |
Symbol (ECMAScript 2015 新增) | “symbol” |
宿主对象(由 JS 环境提供) | 取决于具体实现 |
Function 对象 (按照 ECMA-262 规范实现 [[Call]]) | “function” |
其他任何对象 | “object” |
可以看到 typeof 比较适合用来对 基本数据类型 进行判断,对一些特殊对象都返回"object"(例:Date、Array)
但有一些特殊情况需要注意
typeof null
// JavaScript 诞生以来便如此
typeof null === 'object'
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回"object"。(参考来源)
使用 new 操作符
// 除 Function 外的所有构造函数的类型都是 'object'
var str = new String('String');
var num = new Number(100);
typeof str; // 返回 'object'
typeof num; // 返回 'object'
var func = new Function();
typeof func; // 返回 'function'
这里的原理如上面 instanceof 所示,使用new关键字相当于调用了 Object() 将其进行了一次对象包装(如上述代码所示只有 Function 为例外),所以都返回 ‘object’。
3. Object.prototype.toString.call()
这种方式是最准确、最根本的解决方法。但是返回的字符串处理起来相对来说要麻烦一点。
为了每个对象都能通过
Object.prototype.toString()
来检测,需要以Function.prototype.call()
或者Function.prototype.apply()
的形式来调用,传递要检查的对象作为第一个参数,称为thisArg
。
每个对象都有一个
toString()
方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()
方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString()
返回"[object type]"
,其中type 是对象的类型。
以下是准备的一些例子,使用Object.prototype.toString()
可以检测JavaScript官方定义的所有数据类型。
console.log(Object.prototype.toString.call(123)); // [object Number]
console.log(Object.prototype.toString.call(new Number(123))); // [object Number]
console.log(Object.prototype.toString.call(new Number('123'))); // [object Number]
console.log(Object.prototype.toString.call(Number('123'))); // [object Number]
console.log(Object.prototype.toString.call('123')); // [object String]
console.log(Object.prototype.toString.call(new String('123'))); // [object String]
console.log(Object.prototype.toString.call(new String(123))); // [object String]
console.log(Object.prototype.toString.call(String(123))); // [object String]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call(new Boolean(true))); // [object Boolean]
console.log(Object.prototype.toString.call(new Boolean(1))); // [object Boolean]
console.log(Object.prototype.toString.call(Boolean(0))); // [object Boolean]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(Symbol('123'))); // [object Symbol]
console.log(Object.prototype.toString.call({})); // [object Object]
console.log(Object.prototype.toString.call(Object())); // [object Object]
function Person(name){
this.name = name
}
console.log(Object.prototype.toString.call(new Person('Ace'))); // [object Object]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(new Array)); // [object Array]
console.log(Object.prototype.toString.call(new Date())); // [object Date]
console.log(Object.prototype.toString.call(/^\d{3}$/)); // [object RegExp]
console.log(Object.prototype.toString.call(new RegExp())); // [object RegExp]
console.log(Object.prototype.toString.call(new Map())); // [object Map]
console.log(Object.prototype.toString.call(new Set())); // [object Set]
console.log(Object.prototype.toString.call(new Error())); // [object Error]
console.log(Object.prototype.toString.call(Math)); // [object Math]
注意:而自己定义的构造器函数new出来的实例被检测出来类型仍然是Object。这时需要使用之前提到的instanceof来判断,因为它才是专门用来判断构造器函数相关的类型。
function Person(name){
this.name = name
}
class Animal {
constructor(name) {
this.name = name;
}
}
console.log(new Person() instanceof Person); // true
console.log(new Animal() instanceof Animal); // true