JS 判断数据类型

154 阅读2分钟

typeof

除了null,所有的原始类型都可以使用typeof运算符进行测试。

image.png

  • 从概念上讲,undefined表示值的缺失,null表示对象的缺失(这也可以说明typeof null === 'object'的原因)。
  • NaN(“Not a Number”)

判断数据类型的缺陷

typeof nulltypeof []typeof /a/...这些返回的都是Object

instanceof

语法

object instanceof constructor
  • object 某个实例对象
  • constructor 某个构造函数

描述

instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。

手写instanceof

function myInstanceof(obj, constructor) {
    if (obj === null) return false
    let prototype = Object.getPrototypeOf(obj)
    if (prototype === constructor.prototype) {
        return true
    } else {
      return myInstanceof(prototype, constructor)
    }
}

判断数据类型的缺陷

  1. 对于字面量声明的基础类型无法识别
1 instanceof Number // false
new Number(1) instanceof Number // true
  1. 对于[] instanceof Object这类也会返回true, 所以可能无法准确的判断Array、Date、RegExp等
[] instanceof Array // true
[] instanceof Object // true

Object.prototype.toString()

Object.prototype.toString()是比较完善的判断数据类型的方案。

Object.prototype.toString.call(null)      // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(true)      // '[object Boolean]'
Object.prototype.toString.call(1)         // '[object Number]'
Object.prototype.toString.call('a')       // '[object String]'
Object.prototype.toString.call(new Symbol()) //'[object Symbol]'

Object.prototype.toString.call({})         // '[object Object]'
Object.prototype.toString.call([])         // '[object Array]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(/a/)        // '[object RegExp]'

value.constructor.name;

({}).constructor.name    // 'Object'
[].constructor.name      // 'Array'
new Date().constructor.name  // 'Date'
/a/.constructor.name   'RegExp'

value.constructor.name判断数据类型的缺陷

无法判断字面量声明的基础类型。

Array.isArray()

只是判断是否数组。

MDN官方提供的检查数据类型的方法

function type(value) {
  if (value === null) {
    return "null";
  }
  const baseType = typeof value;
  // 基本类型
  if (!["object", "function"].includes(baseType)) {
    return baseType;
  }

  // Symbol.toStringTag 通常指定对象类的“display name”
  // 它在 Object.prototype.toString() 中使用。
  const tag = value[Symbol.toStringTag];
  if (typeof tag === "string") {
    return tag;
  }

  // 如果它是一个函数,其源代码以 "class" 关键字开头
  if (
    baseType === "function" &&
    Function.prototype.toString.call(value).startsWith("class")
  ) {
    return "class";
  }

  // 构造函数的名称;例如 `Array`、`GeneratorFunction`、`Number`、`String`、`Boolean` 或 `MyCustomClass`
  const className = value.constructor.name;
  if (typeof className === "string" && className !== "") {
    return className;
  }

  // 在这一点上,没有合适的方法来获取值的类型,因此我们使用基本实现。
  return baseType;
}

Symbol.toStringTag

对象可以通过定义Symbol.toStringTag属性来更改Object.prototype.toString()的行为

function MyDate() {
    
}
Object.prototype.toString.call(MyDate) // '[object Function]'

MyDate[Symbol.toStringTag] = 'MyDate'
Object.prototype.toString.call(MyDate) // '[object MyDate]'

Vue中判断数据类型的源码

export const isArray = Array.isArray
export const isMap = (val: unknown): val is Map<any, any> =>
  toTypeString(val) === '[object Map]'
export const isSet = (val: unknown): val is Set<any> =>
  toTypeString(val) === '[object Set]'

export const isDate = (val: unknown): val is Date =>
  toTypeString(val) === '[object Date]'
export const isRegExp = (val: unknown): val is RegExp =>
  toTypeString(val) === '[object RegExp]'
export const isFunction = (val: unknown): val is Function =>
  typeof val === 'function'
export const isString = (val: unknown): val is string => typeof val === 'string'
export const isSymbol = (val: unknown): val is symbol => typeof val === 'symbol'
export const isObject = (val: unknown): val is Record<any, any> =>
  val !== null && typeof val === 'object'

export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
  return (
    (isObject(val) || isFunction(val)) &&
    isFunction((val as any).then) &&
    isFunction((val as any).catch)
  )
}

export const objectToString = Object.prototype.toString
export const toTypeString = (value: unknown): string =>
  objectToString.call(value)

11