一篇搞懂JavaScript 判断类型的几种方法

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'))

参考自Why is 4 not an instance of Number?

总结: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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值