对于数据类型检测笔者以前写过一篇typeof
的JS中数据类型检测方法——typeof,今天就整理下JS中数据类型检测的四种方式的区别:javascript
tyepof [value]
:检测数据类型的运算符[example] instanceof [class]
: 检测某一个实例是否属于这个类[example].constructor===[class]
:检测实例和类关系的,从而检测数据类型Object.prototype.toString.call([value])
:检测数据类型tyepof [value]
typeof
检测的结果首先是一个字符串;“number”
、“string”
、“boolean”
、“undefined”
、“object”
、“function”
、“symbol”
、“bigint”
)NaN
/ Infinity
都是数字类型的,检测结果都是“number”
;typeof null
的结果是“object”
;
BUG
:全部的值在计算中都以二进制编码储存,浏览器中把前三位000
的看成对象,而null
的二进制前三位是000
,因此被识别为对象,可是他不是对象,他是空对象指针,是基本类型值)typeof
普通对象/数组对象/正则对象...
, 结果都是“object”
,这样就没法基于typeof
区分是普通对象
仍是数组对象``...
等了
- 已知有一个变量x,可是咱们没法确认其数据类型,咱们须要有一个判断操做:当x的类型是对象的时候(什么对象均可以),则处理对应的事情
if (typeof x == "object") {
//=>null检测结果也会是"object",因此结果是"object"不必定是对象,还多是null呢
...
}
复制代码
能够用👇的条件进行判断java
if (x != null && typeof x == "object") {
// ...
}
复制代码
console.log(typeof []); //=>"object"面试
console.log(typeof typeof typeof []); //=>"string"数组
需注意:浏览器
因为`typeof`返回的结果永远是一个字符串(字符串中包含了对应的类型),因此连续出现`两个及两个以上typeof检测`的时候,最后结果都是` "string"` bash
true
实例 instanceof 类
TRUE
,不属于返回FALSE
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,因此没法基于这个结果判断是否为普通对象
复制代码
// instanceof检测的实例必须都是引用数据类型的,它对基本数据类型值操做无效
console.log(10 instanceof Number); //=>false
console.log(new Number(10) instanceof Number); //=>true
// instanceof检测机制:验证当前类的原型prototype是否会出如今实例的原型链__proto__上,只要在它的原型链上,则结果都为TRUE
function Fn() {}
Fn.prototype = Object.create(Array.prototype);
let f = new Fn;
console.log(f instanceof Array); //=>true f其实不是数组,由于它连数组的基本结构都是不具有的
复制代码
注意️:它自己不能完成数据类型检测,只是利用它(检测某个实例属否属于这个类的)特征来完成数据检测函数
constructor
的属性值是否是预估的类(利用他的实例数据类型检测)实例.constructor === 类
TRUE
,不属于返回FALSE
实例.constructor
通常都等于 类.prototype.constructor
也就是当前类自己(前提是你的 constructor
并无被破坏)Object
)constructor
,也会形成检测的结果不许确(Object
)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
复制代码
注意:它自己不能完成数据类型检测,利用他的实例数据类型检测(不能重定向)post
这个方法在Object的原型上ui
Object.prototype
上的toString
方法,让toString
方法执行,而且基于call
让方法中的this
指向检测的数据值,这样就能够实现数据类型检测了toString
方法;Object.prototype
上的toString
是用来返回当前实例所属类的信息(检测数据类型的),其他的都是转换为字符串的对象实例.toString()
:toString
方法中的THIS
是对象实例,也就是检测它的数据类型,也就是THIS
是谁,就是检测谁的数据类型Object.prototype.toString.call([value])
因此咱们是把toString
执行,基于call
改变this
为要检测的数据值Object.prototype.toString.call(10)
({}).toString.call(10)
({}).toString===Object.prototype.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]"
复制代码
注意:此方法是基于JS自己专门进行数据检测的,因此是目前检测数据类型比较好的方法this
JQ 中对于数据类型检测,笔者理解的主要仍是利用Object.prototype.toString.call()
方法,也能够说是Object.prototype.toString.call()
能够完成数据类型检测的原理解析;
function toType(obj) {
let class2type = {},
toString = class2type.toString, //=>Object.prototype.toString 检测数据类型
arr = "Boolean Number String Function Array Date RegExp Object Error Symbol".split(" ");
arr.forEach(item => {
class2type["[object " + item + "]"] = item.toLowerCase();
})
/* console.log(class2type); { [object Boolean]: "boolean", [object Number]: "number", [object String]: "string" ...... } */
//传递给个人是null/undefined,直接返回 "null"/"undefined"
if (obj == null) {
return "" + obj;
}
// typeof obj === "object" || typeof obj === "function" =>引用数据类型
// => 若是是基本数据类型值,检测数据类型使用typeof就能够
// => 若是是引用数据类型值,则基于对象的toString就能够
// => toString.call(obj) 检测当前值的数据类型 "[object Xxx]"
// => class2type["[object Xxx]"] 当上一步生成的对象中,基于对应的属性名,找到属性值(所属的数据类型),若是没有则返回 "object"
return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj;
};
console.log(toType(1)); //=>"number"
console.log(toType(NaN)); //=>"number"
console.log(toType([])); //=>"array"
console.log(toType(/^\d+$/)); //=>"regexp"
console.log(toType({})); //=>"object"
console.log(toType(null)); //=>"object"
console.log(toType()); //=>"object"
复制代码
上面咱们已经阐述完数据类型检测四种方式的优缺点;
咱们提到了在Object
原型上的toString
方法,这里顺便提一下另一个在Object
原型上的valueOf
方法
Object
原型上的valueOf
方法每一种数据类型的构造函数的原型上都有
toString
方法;每一种基本数据类型的构造函数的原型上都有
valueOf
方法;Object.prototype
的原型上也有valueOf
方法;
let num1 = 10,
num2 = new Number(10);
console.log(num1);//=> 10
console.log(num1.valueOf());//=> 10
console.log(num1.toString());//=> "10"
console.log(num2);//=>Number {10}
console.log(num2.valueOf());//=> 10
console.log(num2.toString());//=> "10"
复制代码
上面说过只有基本数据类型的构造函数的原型上都有valueOf
方法;Object.prototype
的原型上也有valueOf
方法;
因此数组的构造函数的原型上是没有这个方法的,咱们用数组调取valueOf
方法,其实是经过数组的原型链查找到Object.prototype
的原型上,调取valueOf
的方法;
let arr = [10, 20],
obj = {
xxx: 'xxx'
};
console.log(arr);
console.log(arr.valueOf()); //=>调取的是 Object.prototype.valueOf 原始值
console.log(arr.toString()); //=>调取的是 Array.prototype.toString 转换字符串
console.log(obj);
console.log(obj.valueOf()); //=>调取的是 Object.prototype.valueOf 原始值
console.log(obj.toString()); //=>调取的是 Object.prototype.toString 检测数据类型
复制代码
let num1 = 10,
num2 = new Number(10);
let arr = [10, 20],
obj = {
xxx: 'xxx'
};
复制代码
例如:
ALERT
会把全部要输出的值转换为字符串(隐性转换),像这种隐性转换为字符串的还有不少,例如:字符串拼接、把对象转换为数字(也是先转换为字符串)...
- =>num1.valueOf() 先获取原始值
- =>[[PrimitiveValue]].toString() 把获取的原始值转换为字符串
原题以下:
//=> 下面代码a在什么值状况下会输出1
var a = ?;
if (a == 1 && a == 2 && a == 3) {
console.log(1);
}
复制代码
其中一种解题思路是能够利用valueOf
获取原始值
var a = {
n : 0,
valueOf(){
return ++this.n;
}
};
if (a == 1 && a == 2 && a == 3) {
console.log(1);
}
复制代码