类型检测
一、单一类型检测
1.1 typeof
1.2 instanceOf
1.3 isPrototypeOf
isPrototypeOf()
方法用于测试一个对象是否存在于另一个对象的原型链上。
isPrototypeOf()
与instanceof
有什么区别?
-
a.isPrototypeOf(b)
: 针对a
本身进行检查 -
b instanceof b
: 针对b.prototype
进行检查
语法
prototypeObj.isPrototypeOf(object)
object
: 在该对象的原型链上搜寻
返回值
Boolean
,表示调用对象是否在另一个对象的原型链上。
应用场景
原理(Polyfill)
1.4 constructor
1.5 Object.prototype.toString()
toString()
方法返回一个表示该对象的字符串。该方法旨在重写(自定义)派生类对象的类型转换的逻辑。
语法
console.log({}.toString()); // [object Object]
console.log({ a:1 }.toString()); // [object Object]
返回值
一个表示该对象的字符串, 返回的字符串内容如下:
[object Object]
应用场景
-
场景一、各个数据类型重写或覆盖
Object.prototype.toString()
-
场景二、各个数据类型返回各自的
Symbol.toStringTag
或者标签-
原理:
Object.prototype.toString()
返回"[object Type]"
,这里的Type
是对象的类型。如果对象有Symbol.toStringTag
属性,其值是一个字符串,则它的值将被用作Type
。许多内置的对象,包括Map
和Symbol
,都有Symbol.toStringTag
。一些早于ES6
的对象没有Symbol.toStringTag
,但仍然有一个特殊的标签。它们包括(标签与下面给出的类型名相同):Array
Function
Error
Boolean
Number
String
Date
RegExp
-
注意: 如果对象有
Symbol.toStringTag
属性,对象可以通过定义Symbol.toStringTag
属性来更改Object.prototype.toString()
的行为,从而导致意想不到的结果 -
尝试:
-
返回
Number
的Symbol.toStringTag
或者特殊标签const value = 1;
const reg = /^\[object\s+(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object Number]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); // Number
value[Symbol.toStringTag] = "NumberEdit"; // Number 没有 Symbol.toStringTag,但是有一个特殊的标签 “Number” , 所以不会发生重写 Symbol.toStringTag 的情况
console.log(Object.prototype.toString.call(value)) // [object Number] -
返回
String
的Symbol.toStringTag
或者特殊标签const value = "哈哈";
const reg = /^\[object\s+(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object String]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); // String
value[Symbol.toStringTag] = "NumberEdit"; // String 没有 Symbol.toStringTag,但是有一个特殊的标签 “String”, 所以不会发生重写 Symbol.toStringTag 的情况
console.log(Object.prototype.toString.call(value)) // [object String] -
返回
Boolean
的Symbol.toStringTag
或者特殊标签const value = true;
const reg = /^\[object\s(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object Boolean]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); // Boolean
value[Symbol.toStringTag] = "NumberEdit"; // Boolean 没有 Symbol.toStringTag,但是有一个特殊的标签 “Boolean”, 所以不会发生重写 Symbol.toStringTag 的情况
console.log(Object.prototype.toString.call(value)) // [object Boolean] -
返回
undefined
的Symbol.toStringTag
或者特殊标签const value = undefined;
const reg = /^\[object\s+(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object Undefined]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); // Undefined -
返回
null
的Symbol.toStringTag
const value = null;
const reg = /^\[object\s+(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object Null]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); // Null -
返回
object
的Symbol.toStringTag
或者特殊标签const value = {};
const reg = /^\[object\s+(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object Object]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); //Object
value[Symbol.toStringTag] = "NumberEdit"; // Object 有 Symbol.toStringTag, 所以会发生重写 Symbol.toStringTag 的情况
console.log(Object.prototype.toString.call(value)) // [object NumberEdit] -
返回
Array
的Symbol.toStringTag
const value = [];
const reg = /^\[object\s+(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object Array]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); //Array
value[Symbol.toStringTag] = "NumberEdit"; // Array 有 Symbol.toStringTag, 所以会发生重写 Symbol.toStringTag 的情况
console.log(Object.prototype.toString.call(value)) // [object NumberEdit] -
返回
Date
的Symbol.toStringTag
const value = new Date();
const reg = /^\[object\s+(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object Date]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); //Date
value[Symbol.toStringTag] = "NumberEdit"; // Date 有 Symbol.toStringTag
console.log(Object.prototype.toString.call(value)) // [object NumberEdit] -
返回
RegExp
的Symbol.toStringTag
const value = /a/;
const reg = /^\[object\s+(.*)\]$/;
console.log(Object.prototype.toString.call(value)) // [object RegExp]
const type = reg.exec(Object.prototype.toString.call(value))?.[1];
console.log(type); //RegExp
value[Symbol.toStringTag] = "NumberEdit"; // RegExp 有 Symbol.toStringTag
console.log(Object.prototype.toString.call(value)) // [object NumberEdit]
-
-
-
场景三、自定义对象如何获得
[object MyObject]
类型解决方案: 更改原型上的
[Symbol.toStringTag]
属性即可function Person(){
}
Person.prototype[Symbol.toStringTag] = "Person";
const person = new Person();
console.log(Object.prototype.toString.call(person)); -
场景四、
Object.prototype.toString.call(Boolean.prototype)
结果是什么?
原理(Polyfill)
二、组合类型检测
2.1 基础类型
-
方式一、通过
typeof
export function isPrimitive(value: any): boolean {
return (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'symbol' ||
typeof value === 'boolean'
)
}
2.2 定义类型
-
方式一、是否定义
export function isDef<T>(v: T): v is NonNullable<T> {
return v !== undefined && v !== null
} -
方式二、是否未定义
export function isUndef(v: any): v is undefined | null {
return v === undefined || v === null
}
2.3 对象类型
-
方式一、通过
typeof
export function isObject(obj: any): boolean {
return obj !== null && typeof obj === 'object'
}
三、特殊类型检测
3.1 Promise 类型
export function isDef<T>(v: T): v is NonNullable<T> {
return v !== undefined && v !== null
}
export function isPromise(val: any): val is Promise<any> {
return (
isDef(val) &&
typeof val.then === 'function' &&
typeof val.catch === 'function'
)
}