JS数据类型检测
一.检测类型之前我们需要知道js中有哪些数据类型
一般来说数据类型分为两种:基本数据类型和复杂数据类型
基本数据类型
- String
- Number
- Boolen
- Null
- Undefined
- Symbol
- BigInt
复杂数据类型
- Object
- Array
- Function
- Date
- RegExp
二.检测数据类型的方法
- typeof
typeof 运算符返回一个字符串,表示操作数的类型。
/* 基本数据类型 */
console.log(typeof '') //string
console.log(typeof 1) //number
console.log(typeof true) //boolen
console.log(typeof undefined) //undefined
console.log(typeof null) //object
console.log(typeof Symbol()) //symbol
//看完上面的输出结果肯定会有疑问,都是基本数据类型为啥 typeof null 是object呢?
/*
在javascript最开始使用的是32位系统,js为了性能优化使用低位来储存类型信息
object: 000.
int: 1
double:010
string:100
boolen:110
null:全是0
所以导致 typeof null 为object
*/
/* 复杂数据类型*/
//typeof 判断复杂数据类型除function外都是object,不能准确判断复杂数据类型
console.log(typeof []) //object
console.log(typeof {}) //object
console.log(typeof new RegExp(/^$/)) //object
console.log(typeof new Date()) //object
console.log(typeof function (){}) //function
- instanceof
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
//instanceof本质是来判断构造函数的prototyoe有没有在实例的原型链上的,但是我们可以根据这个特性来判断数据类型。
console.log([] instanceof Array) //true
console.log({} instanceof Object)//true
console.log(new Date() instanceof Date)//true
console.log(new RegExp() instanceof RegExp)//true
//当然用instanceof判断类型也有缺陷:
console.log([] instanceof Object) //true 因为跟据原型链查找机制最终会查找到Object.prototype,所以数组的原型链上会出现Object
console.log(new Number(1) instanceof Object)//true 为什么用 new Number 因为1是一个原始值并不是一个对象,所以需要用new Number来声明
/* 下面来实现一个instanceof */
function myInstanceof(example,classFnc){
if(example == null) return false;//排除 null undefined 原始方法里面并没有排除。
if(typeof example !== 'object' && typeof example !== 'function') return false;
var getProto = Object.getPrototypeOf,
classFncProto = classFnc.prototype,//拿到构造函数的prototype
exampleProto = getProto(example);//获取实例的prototype;
while(true){
if(exampleProto === null) return false //一直找到Object.prototype.prototype为null,这样说明没有找到返回false
if(exampleProto === classFncProto) return true// 如果相等则返回true
exampleProto = getProto(exampleProto)//获取实例prototype的prototype
}
}
console.log(myInstanceof(1,Number))//false
console.log(myInstanceof(new Number(1),Number))//true
console.log(myInstanceof([],Array))//true
console.log(myInstanceof([],Object))//true
console.log(myInstanceof(new Date(),Date))//true
- constructor
Object 实例的 constructor 数据属性返回一个引用,指向创建该实例对象的构造函数。注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。
//我们可以通过实例的constructor指向实例对象的构造函数来判断数据类型检测,constructor比instanceof好的地方在于可以检测基本类型 undefined、null除外
var num = 1;
console.log(num.constructor === Number)//true;
var str = 'str';
console.log(str.constructor === String)//true
var bool = true;
console.log(bool.constructor === Boolean)//true
//而且constructor不会顺着原型链查找
let arr = []
console.log(arr.constructor === Array)//true
console.log(arr.constructor === Object)//false
//当然也有缺点就是constructor可以被随意更改
let obj = {};
obj.constructor = 'AAA';
console.log(obj.constructor === Object);//false 此时obj.constructor : AAA
- Object.prototype.toString
Object.prototype.toString() 返回 "[object Type]",这里的 Type 是对象的类型
// 用这种方法来判断数据类型能精确的判断出数据类型
console.log(Object.protoType.toString(1))//"[object Number]"
console.log(Object.protoType.toString(''))//"[object String]"
console.log(Object.protoType.toString(true))//"[object Boolean]"
console.log(Object.protoType.toString(null))//"[object Null]"
console.log(Object.protoType.toString(undefined))//"[object Undefined]"
console.log(Object.protoType.toString(function(){}))//"[object Function]"
console.log(Object.protoType.toString([]))//"[object Array]"
console.log(Object.protoType.toString({}))//"[object Object]"
console.log(Object.protoType.toString(new Date()))//"[object Date]"
console.log(Object.protoType.toString(Math))//"[object Math]"
console.log(Object.protoType.toString(new RegExp()))//"[object RegExp]"
//当然此方法也有缺点ES6之后内置对象type都是根据Symbol.toStringTag来取,所以导致能更改
const myDate = new Date();
Object.prototype.toString.call(myDate); // [object Date]
myDate[Symbol.toStringTag] = "myDate";
Object.prototype.toString.call(myDate); // [object myDate]
封装类型检测方法
最后用我们所了解的的类型检测方式封装一个简单的类型检测方法
/**
* @param {*} tarValue 目标值
* @returns {string} tarType 返回目标类型
*/
function detectionType(tarValue){
if(typeof tarValue !== 'object' || tarValue === null) return tarValue + '';
var reg = /^\[object (.+?)\]$/;
var typeStr = Object.prototype.toString.call(tarValue);
return typeStr.match(reg)[1].toLowerCase();
}