JS数据类型
js有8种数据类型,其中7种为基础类型(原始值),1种为引用类型(引用值)
基础类型:undefined、Null、Boolean、String、Number、BigInt、Symbol
引用类型:Object(Array、RegExp、Date、Math、Function)
基础类型存储在栈内存中,被引用或被拷贝时,会创建一个完全相等的变量
引用类型存储在堆内存中,存储的是地址,被引用或被拷贝时,可能会出现多个引用指向同一个地址,这涉及到“共享”的概念
区分数据类型的几种方法
1.typeof
typeof可以区分除null之外的原始数据类型
注:typeof null结果为object ,但null不是对象,这是js存在已久的问题,所有的值在计算机中都以二进制编码储存,浏览器种把二进制前三位为000的当作对象,而null的二进制前三位为000,故被识别为了对象,其实不然,它是空对象指针,所以typeof null为object不能作为判断null的方法,如需在if语句中判断是否为null,直接通过===null
来判断即可
NaN/Infinity都是数字类型,检测结果为"number"
typeof只能判断出function这一类的引用值,其余均显示"object"
2.instansceof
instanceof可以判断左边实例对象是否是由右边构造函数生成的,即左边对象是否是右边构造函数 原型链继承 的对象,构造函数的原型只要出现在实例对象的原型链上就返回true
实例对象必须是对象数据类型的,基本数据类型的实例无法检测,即instanceof只能判断引用值,不能判断原始值
字面量方式创建的不能检测,构造函数创建的可以检测
无法判断是否是普通对象,不管是数组对象还是正则对象,都是Object的实例,都会返回true
/instanceof的底层实现代码
/
function myInstanceof(left,right){
//instanceof无法判断基本数据类型,所以开头直接pass
if(typeof left !== "object" || typeof left === null) return false;
//构造函数的原型只要出现在实例对象的原型链上就返回true
let proto = Object.getPrototypeOf(left);//getPrototypeOf是Object对象自带的API,能够得到参数的原型对象
while(1){
if(proto === null) return false;
if(proto === right.prototype) return true;
proto = Object.getPrototypeof(proto);
}
}
console.log(myInstanceof(new Number(123), Number));//true
console.log(myInstanceof(123, Number));//false
3.constructor
判断当前实例的constructor属性值是不是对应的构造函数
实例.constructor === 类
属于返回true,否则返回false
可以检测基本数据类型
不能重定向当前构造函数的原型,否则会造成检测结果不准确
不能给当前实例添加私有属性constructor,否则会造成检测结果不准确
js中的构造函数原型的constructor是不被保护的,用户可以进行修改,因此基于constructor检测的值存在不确定性
不管是单独使用typeof、instanceof、constructor,都不能满足所有场景的需求,而多者混写的方式判断出来的其实也只是大多数的情况,并且写起来比较难受,因此,更加推荐下面的第四种方法
4.Object.prototype.toString.call()
或({}).toString.call()
此方法是基于js本身专门进行数据检测的,是目前检测数据类型比较好的方法
这里的toString()是Object的原型上的方法,可判断原始值,也可判断引用值,输出格式为"[object Xxx]"的字符串
每种数据类型的构造函数的原型上都有toString方法,除了Object.prototype上的toString方法是用于返回当前实例所属构造函数的信息,其余的都是转换为字符串的
对于Object对象,直接调用toString()就能返回[object Object]
对于其他对象需要通过call调用,才能返回正确的类型信息
对象实例.toString()
toString()方法中的this指向实例对象,即检测的是对象实例的数据类型,Object.prototype.toString.call()
就是用call方法将toString方法中的this 指向要检测的数据
只能检测内置类,不能检测自定义类,自定义类会返回[Object Object]
工具方法思路
- 排除null,null虽然是原始值,但由于js的历史遗留问题,其数据类型为object
- typeof 区分原始值(也叫基本数据类型:Number、String、Boolean、Null、Undefined)和引用值(如Object,Function,Array,RegExp,Data等)
- Object.prototype.toString.call() 细分引用值
代码实现
var test = function(e){
var ret = typeof e;
var template = {//引用值对象
'[object Array]':'array',//数组
'[object Object]':'object',//对象
'[object Number]':'number-object',//包装类
'[object Boolean]':'boolean-object',//包装类
'[object String]':'string-object',//包装类
'[object Date]':'date-object',//日期
'[object RegExp]':'regexp-object'//正则表达式
}
if(e == null){//判断是否为null/undefined undefined == null为true
return e;
}else if(ret == 'object'){//引用值
var str = Object.prototype.toString.call(e);
return template[str];
}else{//原始值
return typeof(ret)
}
}