一篇搞懂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

猜你喜欢

转载自blog.csdn.net/qq_33866817/article/details/119810345
今日推荐