前端开发系列037-基础篇之类型检测

本文介绍 JavaScript 中的数据类型,以及这些数据的类型检测方式。

JavaScript 存在很多中数据类型,按照一贯的区分方式,我们把这些数据类型分为两大类,分别是原始(基本)数据类型和对象类型。

其中基本( 原始 )数据类型有6种,分别是 null undefined boolean string number symbol,对象类型则为object,对象类型中包含Object、Array、RegExp、Function、Error、Set、Map、WeakMap等。

在JavaScript 代码中我们经常需要对数据的类型进行检查,检查数据类型的方式主要有四种:

- typeof     关键字
- instanceof 关键字
- Object.prototype.toString.call() 
- constructor 构造器属性
typeof 关键字

typeof 关键字是检查数据类型最简单也最常用的方法。

console.log(typeof "abc")                   /* string */
console.log(typeof 12345)                   /* number */
console.log(typeof true)                    /* boolean */
console.log(typeof undefined)               /* undefined */
console.log(typeof Symbol())                /* symbol */
console.log(typeof null)                    /* object */
console.log(typeof typeof typeof Symbol())  /* string */

console.log(typeof {})                      /* object */
console.log(typeof [])                      /* object */
console.log(typeof /abc/)                   /* object */
console.log(typeof function(){})            /* function */

我们在使用typeof 关键字的时候,有一些注意点。

首先就是 typeof null 得到的结果为object 而非null,这在 JavaScript 语言中被认为(承认)是一个设计错误,typeof null 被判定为 object 的原因在于 null 本身表示什么都没有,所以在计算机中表示为一串0,而计算机内部处理的时候如果读取的数据总是以000开头,那么就将被认为是对象类型的数据。

其次,typeof 关键字在对象类型进行运算的时候得到的都是object,只有函数类型比较特殊得到的是function,也就是说我们无法通过该关键字来检查给定的数据是否是数组、或者是正则表达式等等。如果需要获取这些结构的数据类型,或者说是获取这些数据的构造函数,常用的方式是借用 Object 原型对象上面的 toString 方法来实现,该方法总是会返回一个[object 构造函数]结构的字符串。

Object.prototype.toString 方法

JavaScript 语言中的Object.prototype.toString方法总是会返回[object 构造函数]结构的字符串,其中方括号中前面的object表明该数据是对象类型的,后面的则是创建该实例的构造函数。

如果是一个普通的对象,譬如{name:"zs"},在调用该方法的时候 [代码为:({name:"zs"}).toString()]得到的结果为[object object], 但因为原型链方法覆盖的问题,数组或其它类型的数据则无法直接调用该方法。对于除普通对象外的其它对象类型的数据而言,它们需要通过 call 或 apply 绑定 this 的方式才能调用该方法。

console.log(({}).toString())                              /* [object Object] */
console.log(Object.prototype.toString.call({}))           /* [object Object] */
console.log(Object.prototype.toString.call([]))           /* [object Array] */
console.log(Object.prototype.toString.call(new Function)) /* [object Function]*/
console.log(Object.prototype.toString.call(new RegExp))   /* [object RegExp] */
console.log(Object.prototype.toString.call(new Error))    /* [object Error] */
console.log(Object.prototype.toString.call(new Set))      /* [object Set] */
console.log(Object.prototype.toString.call(new Map))      /* [object Map] */

一般而言Object.prototype.toString 方法很好用,But 它也不是万能的,譬如它无法处理自定义类型的类型检查( 包括自定义构造函数 和 Class 等)。

function Person() {};
let p = new Person;

class Animal {};
let a = new Animal;
console.log(Object.prototype.toString.call(p)) /* [object Object] */
console.log(Object.prototype.toString.call(a)) /* [object Object] */

对于自定义类型的数据,我们需要通过 instanceof 或者是 constructor 来进行检查。

instanceof 关键字 && constructor 构造器属性

JavaScript 语言中的 instanceof 关键字用于检查某个对象是否是指定构造函数创建的实例对象,在检查的时候会检查整条原型链。如果准确点说,那么instanceof 实际上检查的是某个对象( 左值 )是否在指定构造函数( 右值 )的原型链上面,如果在那么就返回 true ,否则的话就返回 false。

console.log(p instanceof Person)                            /* true */
console.log(a instanceof Person)                            /* false */
console.log(a instanceof Animal)                            /* true */
console.log(a instanceof Function, a instanceof Object)     /* false true */

console.log(a.constructor == Person);                       /* false */
console.log(a.constructor == Animal);                       /* true */
console.log(a.constructor == Object);                       /* false */
console.log(p.constructor == Person);                       /* true */

console.log(({}).constructor == Object)                     /* true */
console.log(([]).constructor == Array)                      /* true */

这里试着给出instanceof关键字的实现代码,其实就是个死循环和循环内原型查找而已。

/* instanceof 实现原理 */
function mockInstanceof(instance,constructor){

  let B = constructor.prototype;
  let A = instance.__proto__;

  while(true)
  {
    /* Object.prototype.__proto__ -> null */
    if (A == null){
      return false;
    }
    if (A === B){
      return true;
    }
    A = A.__proto__;   
  }

}

/* 测试数据 */
function Person() { };
function Boy() { };
let p = new Person;
let b = new Boy;

console.log(mockInstanceof(p, Person))          /* true */
console.log(mockInstanceof(p, Object))          /* true */
console.log(mockInstanceof(b, Boy))             /* true */
console.log(mockInstanceof(b, Person))          /* false */

posted on 2022-12-12 10:02  文顶顶  阅读(34)  评论(0编辑  收藏  举报

导航