一篇文章让你学会Js数据类型检测的原理及使用
前置知识:Js中的数据类型
在Js中有两大类型数据,一种是基本数据类型,一种是引用数据类型
1. 基本数据类型
类型 | 名称 |
---|---|
string | 字符串 |
number | 数字 |
boolean | 布尔值 |
null | 空对象指针 |
undefined | 未定义 |
symbol | 唯一值 |
bigint | 大整数 |
2. 引用数据类型
类型 | 名称 |
---|---|
object | 标准普通对象 |
Array、RegExp、Date、Math、Error… | 标准特殊对象 |
Number、String、Boolean… | 非标准特殊对象 |
function | 可调用/可执行对象(函数) |
Js中的类型检测
回归正题,我们来讲讲Js中的类型检测都会用到哪些方法,以及这些方法的原理机制是怎么样的
本文列举了几个Js数据中常用的类型检测方法:
- typeof
- instanceof
- constructor
- Object.prototype.toString.call
- Array.isArray()
- isNaN
我们先说说最常用的typeof
1.typeof
typeof返回的结果是字符串,字符串中包含了对应的数据类型
来看看一些检测结果:
检测 | 结果 |
---|---|
typeof 1 | number |
typeof NaN (非数字) | number |
typeof Infinity (无穷) | number |
typeof ‘’ (空字符串) | string |
typeof null | object |
typeof undefined | undefined |
typeof symbol | symbol |
typeof 10n | bigint |
typeof {} | object |
typeof [] | object |
typeof new Number | object |
typeof function(){} | function |
数据类型的底层二进制表示
在讲typeof的检测机制及原理之前,我们要知道数据类型在计算机的底层都是怎么表示的
所有数据类型值,在计算机底层都是按照‘64位’的二进制进行存储的。
这里只列举数据类型二进制表示的前三位
类型 | 二进制码前三位 |
---|---|
对象 | 000 |
字符串 | 100 |
浮点数 | 010 |
布尔值 | 110 |
null | 000…(64个都是0) |
undefined | -2^30 |
typeof的检测机制:
- typeof是按照二进制进行检测类型的。
- 比如,二进制的前三位是0,就会被认为是对象,然后再去看有没有实现call方法,如果实现了,返回’function’,没有实现,则返回’object’。
- null的二进制表示是64个零 而开头是000会被判定为对象,所以typeof null的结果是‘object’ ,这也是typeof的局限性
2.instanceof
检测当前实例是否属于这个类,只要当前类出现在实例的原型链上,结果都是true
let arr=[];
console.log(arr instanceof Array);//true
console.log(arr instanceof RegExp);//false
console.log(arr instanceof Object);//true
由于我们可以肆意地修改原型的指向,所以检测出来的结果可能是不准的
function Fn(){
this.x=100
}
Fn.prototype=Array.prototype;
let f=new Fn;
console.log(f,f instanceof Array);//true
不能检测基本数据类型
console.log(1 instanceof Number);//false
附上手写版instanceof
const instance_of=function instance_of(L,R){
let O = R.prototype;
L = L.__proto__;
while (true) {
if (L === null) {
return false;
}
if (L === O) {
return true;
}
L = L.__proto__
}
}
let num=1;
let arr = [];
let obj = {
name: '小明'
};
console.log(instance_of(num, String));//false
console.log(instance_of(arr, Array));//true
console.log(instance_of(obj, Array));//false
console.log(instance_of(obj, Object));//true
3.constructor
对象的原型链下的一个属性:constructor
比instanceof稍微好用一点(基本类型也支持)
let arr = [];
console.log(arr.constructor ===Array); //true
console.log(arr.constructor === RegExp); //false
console.log(arr.constructor=== Object); //false
let n=1;
console.log(n.constructor===Number);//true
同样的问题,constructor也可以随便改,所以也不一定准确
Number.prototype.constructor='ABC';
let n=1;
console.log(n.constructor===Number);//false
4.Object.prototype.toString.call(最准确)
这个是标准的检测数据类型的方法
检测 | 结果 |
---|---|
Object.prototype.toString.call(1) | ‘[object Number]’ |
Object.prototype.toString.call(NaN) | ‘[object Number]’ |
Object.prototype.toString.call(“”) | ‘[object String]’ |
Object.prototype.toString.call(true) | ‘[object Boolean]’ |
Object.prototype.toString.call(Symbol(‘abc’)) | ‘[object Symbol]’ |
Object.prototype.toString.call({}) | ‘[object Object]’ |
Object.prototype.toString.call([]) | ‘[object Array]’ |
Object.prototype.toString.call(/^$/) | ‘[object RegExp]’ |
Object.prototype.toString.call(new Date()) | ‘[object Date]’ |
Object.prototype.toString.call(function(){}) | ‘[object Function]’ |
Object.prototype.toString.call(null) | ‘[object Null]’ |
Object.prototype.toString.call(undefined) | ‘[object Undefined]’ |
上图
Object.prototype.toString.call的检测原理:
Object.prototype.toString不是转换为字符串,是返回当前实例所属类的信息,结构为:’[object 所属的类]’
let obj={
name:'小明'
}
console.log(obj.toString()); //[object Object]
toString方法执行,this是obj,所以检测的结果是obj它的所属类信息
所以我们只要把Object.prototype.toString执行,让它里面的this变为要检测的值(也就是call方法),那就能返回当前所属类的信息
5.Array.isArray()
判断是否是数组
console.log(Array.isArray([]));//true
console.log(Array.isArray(new Array()));//true
6.isNaN
isNaN() 函数用于检查其参数是否是非数字值。
原理:isNaN函数接受一个参数,会先调用Number()方法尝试将参数转换为数值型,再进行判断。
console.log(isNaN(123));//false
console.log(isNaN('123'));//false
console.log(isNaN(true));//false
console.log(isNaN({}));//true
console.log(isNaN(NaN));//true
总结
Object.prototype.toString.call是最准确最标准的,但是略麻烦,typeof只是对null和对象这些不太好用,一般都结合typeof和Object.prototype.toString.call一起使用。
真实项目当中,基本数据类型除了null以外都可以用typeof,引用数据类型里面function也可以用typeof,对象和null的话就用Object.prototype.toString.call即可。
感谢读者的耐心观看,如果觉得这篇文章对您有所帮助,麻烦点赞收藏噢😋