判断数据类型的三种方法(封装判断数据类型的函数)

判断一个数据的类型,比较常用的有下面几种方式:

  • typeof
  • instanceof
  • Object.prototype.toString.call(xxx)

typeof

判断一个数据的类型,用得最多的就是 typeof 操作符, 但是使用 typeof 常常会遇到以下问题:

  • 无法判断 null
  • 无法判断除了 function 之外的引用类型。
    // 可以判断除了 null 之外的基础类型。
    console.log(typeof true); // 'boolean'
    console.log(typeof 100); // 'number'
    console.log(typeof "abc"); // 'string'
    console.log(typeof 100n); // 'bigint'
    console.log(typeof undefined); // 'undefined'
    console.log(typeof Symbol("a")); // 'symbol'
    
    // 无法判断 null。
    console.log(typeof null); // 输出 'object',原因在文章末尾解释。
    
    // 无法判断除了 function 之外的引用类型。
    console.log(typeof []); // 'object'
    console.log(typeof {}); // 'object'

    instanceof

    typeof 无法精确地判断引用类型,这时,可以使用 instanceof 运算符,如下代码所示:

    console.log([] instanceof Array); // true
    
    const obj = {};
    console.log(obj instanceof Object); // true
    
    const fn = function () {};
    console.log(fn instanceof Function); // true
    
    const date = new Date();
    console.log(date instanceof Date); // true
    
    const re = /abc/;
    console.log(re instanceof RegExp); // true

    但是 instanceof 运算符一定要是判断对象实例的时候才是正确的,也就是说,它不能判断原始类型,如下代码所示:

    const str1 = "qwe";
    const str2 = new String("qwe");
    
    console.log(str1 instanceof String); // false,无法判断原始类型。
    console.log(str2 instanceof String); // true

    typeof 可以判断原始类型,instanceof 可以判断引用类型,但是当数据为null是,它们无法判断,我们可以直接判断变量全等于 null,如下代码所示:

    function getType(target) {
      // ...
      if (target === null) {
        return "null";
      }
      // ...
    }

    现在,判断原始类型和引用类型的思路都有了,接下来就是动手写代码的事,但是真的去写就会发现,使用 instanceof 操作符来判断类型返回的是 true 或者 false,写起来会非常麻烦。

    其实, instanceof 运算符本来是用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上的,只是刚好可以用来判断类型而已,所以在这里才会讨论它,实际上用它来判断类型代码写起来不是很方便。

    这时,Object.prototype.toString 出场了,实际项目中要封装判断类型的工具函数一般都是用的它。

Object.prototype.toString.call(xxx)

调用 Object.prototype.toString 方法,会统一返回格式为 [object Xxx] 的字符串,用来表示该对象(原始类型是包装对象)的类型。

需要注意的是,在调用该方法时,需要加上 call 方法(原因后文解释),如下代码所示:

// 引用类型
console.log(Object.prototype.toString.call({})); // '[object Object]'
console.log(Object.prototype.toString.call(function () {})); // "[object Function]'
console.log(Object.prototype.toString.call(/123/g)); // '[object RegExp]'
console.log(Object.prototype.toString.call(new Date())); // '[object Date]'
console.log(Object.prototype.toString.call(new Error())); // '[object Error]'
console.log(Object.prototype.toString.call([])); // '[object Array]'
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 WeakMap())); // '[object WeakMap]'
console.log(Object.prototype.toString.call(new WeakSet())); // '[object WeakSet]'

// 原始类型
console.log(Object.prototype.toString.call(1)); // '[object Number]'
console.log(Object.prototype.toString.call("abc")); // '[object String]'
console.log(Object.prototype.toString.call(true)); // '[object Boolean]'
console.log(Object.prototype.toString.call(1n)); // '[object BigInt]'
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("a"))); // '[object Symbol]'

有了上面的基础,我们就可以统一调用 Object.prototype.toString 方法来获取数据具体的类型,然后把多余的字符去掉即可,只取 [object Xxx] 里的 Xxx

不过使用 Object.prototype.toString 判断原始类型时,会进行装箱操作,产生额外的临时对象,为了避免这一情况的发生,我们也可以结合 typeof 来判断除了 null 之外的原始类型,于是最后的代码实现如下:

function getType(target) {
  // 先进行 typeof 判断,如果是基础数据类型,直接返回。
  const type = typeof target;
  if (type !== "object") {
    return type;
  }

  // 如果是引用类型或者 null,再进行如下的判断,正则返回结果,注意最后返回的类型字符串要全小写。
  return Object.prototype.toString
    .call(target)
    .replace(/^\[object (\S+)\]$/, "$1")
    .toLocaleLowerCase();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值