详解js数据类型检测的四种方法

541 阅读6分钟

开篇简述

本篇博文将从以问答的方式,带大家详细了解一下js中的数据类型检测


1.js数据类型检测有几种?

  • js数据类型检测有四种,分别为
    • typeof([value)
    • [实例] instanceof [类]
    • constructor
    • Object.prototype.toString.call([value])

2.这几个方法有什么区别?(这样问其实是想看看你对这些方法的原理熟悉多少)

2.1 typeof

  • 用法:typeof [value] 返回结果是一个字符串(字符串中包含了对应的数据类型)
  • 特性:使用起来简单,基本数据类型值基本上都可以有效检测,引用数据类型值也可以检测出来 "number"/"string"/"boolean"/"undefined"/"symbol"/"bigint"/"object"/"function"
  • 缺陷:对于数组、普通对象、正则等,返回结果都是"object",所以无法基于typeof细分对象数据类型
  • 下面给出一些例子供大家参考
        console.log(typeof 1);//='number'
   	console.log(typeof '1');//=>'string'
   	console.log(typeof false);//=>'boolean'
   	console.log(typeof null);//=>'object'
   	console.log(typeof undefined);//=>'undefined'
   	console.log(typeof []);//=>'object'
   	console.log(typeof {});//=>'object'
   	console.log(typeof function(){});//=>'function'
   	console.log(typeof 9007199254740991n);//=>'bigint'
   	console.log(typeof Symbol(1));//=>'symbol'
   	//这里没按需要特别注意的是,连续两个或以上的typeof 返回结果必定是'string
   	typeof typeof [] === "string"
   	//因为null是一个空指针,所以typeof检测结果为一个对象
   	typeof null === "object"

2.2 instanceof

  • 用法:[实例] instanceof [类]:用来检测当前实例是否属于这个类。
  • instanceof检测机制:验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为TRUE
  • 特性:基于这种方式,可以弥补typeof无法细分对象类型的缺点(想检测这个值是否为数组,只需要看他是否为Array类的实例即可)
  • 缺陷:
    • 1)instanceof检测的实例必须都是引用数据类型的,它对基本数据类型值操作无效
    • 2)不管是数组对象还是正则对象,都是Object的实例,检测结果都是TRUE,所以无法基于这个结果判断是否为普通对象
    • 3)由于instanceof的检测机制造成的,当我们收到你的改变一个函数的原型时,会出现未知的错误
  • 下面给出一些例子供大家参考
    //==================基础检测
    console.log(typeof arr); //=>"object"
    console.log(arr instanceof Array); //=>true
    console.log(arr instanceof RegExp); //=>false
    //=================================缺陷1
    console.log(10 instanceof Number); //=>false
    console.log(new Number(10) instanceof Number); //=>true
    //=================================缺陷2
    console.log(arr instanceof Object); //=>true 
    //=================================缺陷三
    function Fn() {}
    Fn.prototype = Object.create(Array.prototype);
    let f = new Fn;
    console.log(f instanceof Array); //=>true f其实不是数组,因为它连数组的基本结构都是不具备的 

2.3 constructor

  • 用法&检测机制:constructor利用类和实例的关系,实例.constructor 一般都等于 类.prototype.constructor 也就是当前类本身(前提是你的constructor并没有被破坏)
  • 特性:不稳定并且不安全
  • 缺陷:JS中的constructor是不被保护的(用户可以自己随便改),这样基于constructor检测的值存在不确定性(但是真实项目中,没有人会改内置类的constructor)
  • 下面给出一些例子供大家参考
    let arr = [],
    	obj = {},
    	num = 10;
    console.log(arr.constructor === Array); //=>true
    console.log(arr.constructor === Object); //=>false
    console.log(obj.constructor === Object); //=>true
    console.log(num.constructor === Number); //=>true 

-------------------------------华丽的分割性---------------------------------------

介绍了前三种js数据类型检测方法,大家也看到了基本上都存在有一定的缺陷,先面我们介绍一种完美的检测方法。

2.4 Object.prototype.toString.call([value])

JS中基本上不存在局限性的数据类型检测方式: => Object.prototype.toString.call([value]) => 基于它可以有效的检测任何数据类型的值

  • 检测机制:
//找到Object.prototype上的toString方法,让toString方法执行,并且基于call让方法中的this指向检测的数据值,这样就可以实现数据类型检测了
	//=>Object.prototype.toString.call(10)
	// =>({}).toString.call(10)
	// =>({}).toString===Object.prototype.toString
	
	//获取结果的结构
	//"[object 当前数据值所属的构造函数]"
  • 小技巧
//简化字符,利用原型连机制让一个空对象去调用object的toString方法
let class2type = {};
let toString = class2type.toString; //=>Object.prototype.toString
  • 下面给出一些例子供大家参考
    console.log(toString.call(10)); //=>"[object Number]"
    console.log(toString.call(NaN)); //=>"[object Number]"
    console.log(toString.call("xxx")); //=>"[object String]"
    console.log(toString.call(true)); //=>"[object Boolean]"
    console.log(toString.call(null)); //=>"[object Null]"
    console.log(toString.call(undefined)); //=>"[object Undefined]"
    console.log(toString.call(Symbol())); //=>"[object Symbol]"
    console.log(toString.call(BigInt(10))); //=>"[object BigInt]"
    console.log(toString.call({xxx:'xxx'})); //=>"[object Object]"
    console.log(toString.call([10,20])); //=>"[object Array]"
    console.log(toString.call(/^\d+$/)); //=>"[object RegExp]"
    console.log(toString.call(function(){})); //=>"[object Function]"

3.拓展一下toString方法和valueOf方法

3.1 valueOf()

  • JavaScript调用valueOf方法将对象转换为原始值。你很少需要自己调用valueOf方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。例如alert、字符串拼接、把对象转换为数字(都是先调用其valueOf方法获取其原始值然后调用toSting方法转换为字符串)
  • 每一种基本数据类型的构造函数的原型上都有valueOf方法,他们都会覆盖此object上的方法以返回适当的值。如果对象没有原始值,则valueOf将返回对象本身。

3.2 toString()

  • 每一种数据类型的构造函数的原型上都有toString方法;
  • 除了Object.prototype上的toString是用来返回当前实例所属类的信息(检测数据类型的),其余的都是转换为字符串的 对象实例.toString() :toString方法中的THIS是对象实例,也就是检测它的数据类型,也就是THIS是谁,就是检测谁的数据类型
  • 下面给出一些例子供大家参考
    //这些打印单出的都是数据类型的结构,可以直接查看其构造函数的原型上都包含toString方法
    //除了 null 和 undefined之外,所有基本类型都有其对应的包装对象
    //==========基本数据类型
    console.dir(Number);
    console.dir(String);
    console.dir(Symbol);
    console.dir(Boolean);
    console.dir(BigInt);
    //=========引用数据类型
    console.dir(Array);
    console.dir({});
    console.dir(RegExp);
    console.dir(function(){});

3.3下面通过一道经典面试题带你了解一下这两种方法在js的使用


/*解题思路:
*   1.当将对象b当做属性存入a中,其隐性转换,先调用对象的valueOf方法然后在调用其toString方法
*   最后存入a中的事a[object Object]='我好帅'。
*   2.重复一的步骤,相当于将a[object Object]的值修改成'你好美';
*/
let a={}, b={n:'1'}, c={m:'2'};
console.log(b.valueOf());//{n: "1"}
console.log(b.toString());//[object Object]
a[b]='我好帅';
a[c]='你好美';  
console.log(a[b]);//=>'你好美'

结语:

如果觉得对你有帮助,请动动你的小手点个赞鼓励一下我吧.持续更新前端优质内容