JavaScript 数据类型判断

(生活的道路一旦选定,就要勇敢地走到底,决不回头。——左拉)

在这里插入图片描述

typeof

typeof是在javascript编码过程中最常用的判断数据类型的方法,常用来判断数字,字符串,布尔值和undefind

console.log(typeof 1); // number
console.log(typeof ''); // string
console.log(typeof true); // boolean
console.log(typeof false); // boolean
console.log(typeof undefined); //undefined

但不能用来判断复杂数据类型,比如以下案例

console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof null); // object

这是因为javascript中的数据类型为两大类,原始值和对象值,其实也就是基础类型和引用类型。
基础类型有undefined,null,boolean,number,string
引用类型有array,object,date,regexp,function等。
每当使用typeof时,v8引擎会判断该数型的类型,如果是基础类型,则返回对应的类型字符串,如果是引用类型,则统一返回object。
需要注意的是typeof null也会返回object,这是js早期的bug一直没解决,正常情况下null就是null。
关于 typoef null等于object的说明
日常判断基本类型使用typeof的话,问题不大。但假如要判断某一个属性的类型是否是数组就做不到了,因为对于typeof来说,数组和对象都是object。并且在一些复杂的业务场景中,还要对类与类之间进行判断,比如A类是否属于B类等自定义对象的类型检查场景,typeof就更无法满足了。

instanceof

为了解决typeof上述中无法解决的业务场景,js还提供了instanceof来通过原型链和原型的比较来达到类型检查的目的。

console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
class Student { }
const student = new Student();
class Car { }
const car = new Car();
class Train extends Car { }
const train = new Train();
console.log(student instanceof Car); // false
console.log(car instanceof Car); // true
console.log(train instanceof Car); // true

其原理还要从js的原型链和原型说起

原型和原型链

如果要自己实现一个instanceof,那么就是这样

const instanceof_custom = (A, B) => {
  let L = A.__proto__;
  const R = B.prototype;
  while (true) {
    if (L === null)
      return false;

    if (R === L)  // 当 R 显式原型 严格等于  L隐式原型 时,返回true
      return true;

    L = L.__proto__;
  }
};

通过代码可以看出,通过递归查找A原型链上的原型来对比B的原型是否相等来达到类型判断的目的,一直到原型链为null时终止。
虽然这样能判断数组和对象了,但又带来了新的问题,比如以下示例

console.log([] instanceof Object); // true
console.log({} instanceof Object); // true
console.log(new Number() instanceof Object); // true
console.log(new String() instanceof Object); // true
console.log(new Boolean() instanceof Object); // true

由于数组和对象的原型链上都有object,就导致他们在用原型链和原型进行对比的时候就会出现相等的情况。

Object.prototype.toString.call

为了解决上述问题,js又提供了Object.prototype.toString()方法。
在js中每一个类型都有着自己的toStirng方法,他们各自返回自己转换成字符串之后的结果,比如

const str = '123';
const number = 123;
const fun = () => { };
const boolean = true;
const array = [1, 2, 3];
const obj = {};
const cls = class { }
console.log(str.toString()); // '123'
console.log(number.toString()); // '123'
console.log(fun.toString()); // '() => { }'
console.log(boolean.toString()); // 'true'
console.log(array.toString()); // '1,2,3'
console.log(obj.toString()); // '[object Object]'
console.log(cls.toString()); // 'class { }'

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属性的话,就业能够达到自定义标签的目的。

class ValidatorClass {
  get [Symbol.toStringTag]() {
    return 'Validator';
  }
}

Object.prototype.toString.call(new ValidatorClass()); // "[object Validator]"

在这里我们先我们删除Array自身的toString方法,然后让它通过原型链来使用上层Object的toString方法来测试一下。

const array = [1, 2, 3];
console.log(array.toString()); // ‘1,2,3’
delete Array.prototype.toString;
console.log(array.toString()); // ‘[object Array]’

至此,解决了instanceof判断对象的问题,但我们在实际应用中最好不要删除原型方法,这样会给程序造成极大的隐患。
那么就可以用js中的call方法来改变this指向,替换Object内部属性值的目的。让Object的toString方法读取Array的特殊标签,那么就可以返回‘[object Array]’了

结论

综上所述,三种判断js类型的方法各有所长,typeof写法简单便于理解,instanceof善于判断自定义对象,Object.prototype.toString.call虽然写起来稍复杂,但除了自定义对象,其他的类型都可以进行判断
至于只用哪一种,还要结合业务场景来进行选择。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值