跳到主要内容

类型检测

2023年02月08日
柏拉文
越努力,越幸运

一、单一类型检测


1.1 typeof

1.2 instanceOf

1.3 isPrototypeOf

isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上。

注意
  1. 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。许多内置的对象,包括 MapSymbol,都有 Symbol.toStringTag。一些早于 ES6 的对象没有 Symbol.toStringTag,但仍然有一个特殊的标签。它们包括(标签与下面给出的类型名相同):

      • Array
      • Function
      • Error
      • Boolean
      • Number
      • String
      • Date
      • RegExp
    • 注意: 如果对象有Symbol.toStringTag属性,对象可以通过定义 Symbol.toStringTag 属性来更改 Object.prototype.toString() 的行为,从而导致意想不到的结果

    • 尝试:

      • 返回NumberSymbol.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]
      • 返回StringSymbol.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]
      • 返回BooleanSymbol.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]
      • 返回undefinedSymbol.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
      • 返回nullSymbol.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
      • 返回objectSymbol.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]
      • 返回ArraySymbol.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]
      • 返回DateSymbol.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]
      • 返回RegExpSymbol.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'
)
}