JS中的数据类型检测
1.检测方法
- tyepof [value] 检测数据类型的运算符
- [example] instanceof [class] 检测某一个实例是否属于这个类
- [example].constructor===[class] 检测实例和类关系的,从而检测数据类型
- Object.prototype.toString.call([value]) 检测数据类型
2.typeof的细节点:
typeof 检测的结果首先是一个字符串,字符串中包含了对应的数据类型(例如:"number"、"string"、"boolean"、"undefined"、"object"、"function"、"symbol"、"bigint")
console.log(typeof 1);//=>'number'
console.log(typeof NaN);//=>'number'
console.log(typeof Infinity);//=>'number'
console.log(typeof "aa");//=>"string"
console.log(typeof true);//=>"boolean"
console.log(typeof null);//=>"object" 正确答案是 'null'
console.log(typeof undefined);//=>"undefined"
console.log(typeof function(){});//=>"function"
console.log(typeof {});//=>"object"
console.log(typeof []);//=>"object"
2.1. 特殊的检测结果:
- NaN / Infinity 都是数字类型的,检测出来的结果是 "number"
- typeof null 的结果是 "object"(这个是浏览器的BUG:所有的值在计算中都已二进制编码存储,浏览器中把前三位是000的当做对象,而null的二进制前三位就是000,所以被识别为对象,但是它不是对象,它是空对象指针,是基本类型值)
- typeof 普通对象/数组对象/正则对象... 结果都是"object",这样就无法基于typeof区分是普通对象还是数组对象等了
/*
* 基于typeof检测出来的结果
* 1. 首先是一个字符串
* 2. 字符串中包含对应的类型
*/
let a = NaN;
console.log(typeof a); //=>'number'
* 局限性
* 1. typeof null => "object" 但是null并不是对象
* 2. 基于typeof无法细分出当前值是普通对象还是数组对象等,
因为只要是对象数据类型,返回的结果都是"object"
*/
2.2 面试题
-
1.检测数据类型:"string"由于typeof返回的结果永远是一个字符串(字符串中包含了对应的类型)
-
2.所以连续出现两个及两个以上typeof检测的时候,最后结果都是 "string"
console.log(typeof []); //=>"object"
console.log(typeof typeof typeof []);
=>typeof typeof "object"
=>typeof "string"
=>"string"
- 3.已知有一个变量x,但是我们无法确认其数据类型,我们需要有一个判断操作:当x的类型是对象的时候(什么对象都可以),则处理对应的事情
if (x != null && typeof x == "object") {
// ...
}
计算结果:
1.console.log(alert(1));
=>先执行ALERT(输出"1"),然后把ALERT执行的返回结果再输出 =>undefined
2.typeof undefined; //=>"undefined" typeof返回的结果首先是一个字符串
3.console.log(parseInt(undefined));
//=>parseInt(undefined) =>parseInt("undefined") =>NaN
4.isNaN(undefined);
//=>isNaN检测值,如果值不是数字类型,先基于Number把其转换为数字类型,
然后再检测 =>Number(undefined) =>NaN =>isNaN(NaN) =>true
2.[example] instanceof [class] 检测某一个实例是否属于这个类
- 1.基于这种方式,可以弥补typeof无法细分对象类型的缺点(想检测这个值是否为数组,只需要看他是否为Array类的实例即可)
let arr = [10, 20];
console.log(typeof arr); //=>"object"
console.log(arr instanceof Array); //=>true
console.log(arr instanceof RegExp); //=>false
console.log(arr instanceof Object); //=>true
//不管是数组对象还是正则对象,都是Object的实例,检测结果都是TRUE,
//所以无法基于这个结果判断是否为普通对象
- 2.instanceof检测机制:验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为TRUE
function Fn() {}
Fn.prototype = Object.create(Array.prototype);
let f = new Fn;
console.log(f instanceof Array); //=>true
//f其实不是数组,因为它连数组的基本结构都是不具备的
- 3.instanceof检测的实例必须都是引用数据类型的,它对基本数据类型值操作无效
console.log(10 instanceof Number); //=>false
console.log(new Number(10) instanceof Number); //=>true
3.[example].constructor===[class] 检测实例和类关系的,从而检测数据类型
- 1.constructor:利用类和实例的关系,实例.constructor 一般都等于 类.prototype.constructor 也就是当前类本身(前提是你的constructor并没有被破坏)
- 2.但是这种方式也是不保险的,因为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
4.Object.prototype.toString.call([value]) 检测数据类型
- 1.JS中基本上不存在局限性的数据类型检测方式: Object.prototype.toString.call([value]);基于它可以有效的检测任何数据类型的值
- 2.找到Object.prototype上的toString方法,让toString方法执行,并且基于call让方法中的this指向检测的数据值,这样就可以实现数据类型检测了
- Object.prototype.toString.call(10)
- ({}).toString.call(10)
- ({}).toString===Object.prototype.toString
- 3.获取结果的结构
- "[object 当前数据值所属的构造函数]"
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]"
- 4.每一种数据类型的构造函数的原型上都有toString方法;
console.log(Number.prototype.toString);
//=>ƒ toString() { [native code] }
console.log(Number.prototype);
//=>展开valueOf0:ƒ valueOf()
console.log(String.prototype);
//=>toString:ƒ toString();valueOf0:ƒ valueOf()
console.log(Boolean.prototype);
//=>toString:ƒ toString();valueOf0:ƒ valueOf()
console.log(Array.prototype);
//=>toString:ƒ toString();
console.log(Object.prototype);
//=>toString:ƒ toString();valueOf0:ƒ valueOf()
console.log(RegExp.prototype);
//=>toString:ƒ toString();
console.dir(Function.prototype);
//=>toString:ƒ toString();
console.log(Symbol.prototype);
//=>toString:ƒ toString();valueOf0:ƒ valueOf()
console.log(BigInt.prototype);
//=>toString:ƒ toString();valueOf0:ƒ valueOf()
-
5.每一种基本数据类型的构造函数的原型上都有valueOf方法;Object.prototype的原型上也有valueOf方法;
- 除了Object.prototype上的toString是用来返回当前实例所属类的信息(检测数据类型的),其余的都是转换为字符串的
- 对象实例.toString() :toString方法中的THIS是对象实例,也就是检测它的数据类型,也就是THIS是谁,就是检测谁的数据类型 =>Object.prototype.toString.call([value]) 所以我们是把toString执行,基于call改变this为要检测的数据值
console.log((10).toString());//=>"10"
console.log((true).toString());//=>'true'
console.log([10,20].toString());//=>'10,20'
console.log((function () {}).toString());//=>"function () {}"
console.log(({}).toString());//=>[object Object]
- 6.ALERT会把所有要输出的值转换为字符串(隐性转换),像这种隐性转换为字符串的还有很多,例如:字符串拼接、把对象转换为数字(也是先转换为字符串)...
- num1.valueOf() 先获取原始值
- [[PrimitiveValue]].toString() 把获取的原始值转换为字符串
let num1 = 10,
num2 = new Number(10);
let arr = [10, 20],
obj = {
xxx: 'xxx'
};
// valueOf是获取原始值 [[PrimitiveValue]]
// toString是将原始值转换为字符串
console.log(num1);//=>10
console.log(num1.valueOf());//=>10
console.log(num1.toString());//=>'10'
console.log(num2);//=>{__proto__: Number [[PrimitiveValue]]: 10}
console.log(num2.valueOf());//=>10
console.log(num2.toString()); //=>'10'
console.log(arr);//=>[10, 20]
console.log(arr.valueOf());//=>[10, 20]
//=>Object.prototype.valueOf 原始值
console.log(arr.toString());//=>'10, 20'
//=>Array.prototype.toString 转换字符串
console.log(obj);//=>{xxx: "xxx"}
console.log(obj.valueOf());//=>{xxx: "xxx"}
//=>Object.prototype.valueOf 原始值
console.log(obj.toString());//=>'[object Object]'
//=>Object.prototype.toString 检测数据类型