一、typeof
-
tyepof [value] :检测数据类型的运算符
-
返回值:返回字符串, 字符串中包含了对应的数据类型(例如: “number”、“string”、“boolean”、“undefined”、“object”、“function”、“symbol”、“bigint”)
typeof NaN
"number"
typeof 2
"number"
typeof unll
"undefined"
typeof null
"object"
typeof undefined
"undefined"
typeof {}
"object"
typeof []
"object"
typeof Boolean
"function"
typeof Number
"function"
typeof Object
"function"
typeof function(){}
"function"
typeof '23'
"string"
typeof true
"boolean"
typeof Infinity
"number"
typeof new Number(1)
"object"
-
优点:使用起来简单,基本数据类型值基本上都可以有效检测,引用数据类型值也可以检测出来
-
局限性
【1】 NaN / Infinity/ 2 都是数字类型的,检测结果都是“number”;
【2】 typeof null 的结果是“object”;
【3】 Date/Object/RegExp/Number 都是返回function,不能判断具体类型
【4】 {}/[] 都是返回"object",无法基于typeof 区分是普通对象还是数组对象
(这是浏览器的BUG:所有的值在计算中都以二进制编码储存,浏览器中把前三位000的当作对象,而null的二进制前三位是000,所以被识别为对象,但是他不是对象,他是空对象指针,是基本类型值)
- 应用场景
我们不需要确认其具体数据类型,但要知道是对象类型(任何对象),啥时候会这样用呢?比如跟后台联调,大概数据结构确定,可以这么使用,区分null或者undefined 和 对象
if (typeof x == "object") {
//=>null检测结果也会是"object",所以结果是"object"不一定是对象,还可能是null呢
...
}
<!--可以这样判断-->
if (x != null && typeof x == "object") {
// ...
}
二、instanceof
[example] instanceof [class] : 检测某一个实例的原型链上是否市这个类的原型属性
具体详情,参考我的 结合实例对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,所以无法基于这个结果判断是否为普通对象
let a = new String();
console.log(a instanceof String); //true
var b = '2'
console.log(b instanceof String); // false
var b = String('2')
console.log(b instanceof String); //false
var b = {a:1}
console.log(b instanceof Object); // true
instanceof检测的实例必须都是引用数据类型的,它对基本数据类型值操作无效
- 局限性
【1】 要求检测的实例必须是对象数据类型的
【2】 不能检测出基本数据类型, 构造函数创建的可以检测
【3】 不管是数组对象还是正则对象,都是Object的实例,检测结果都是true,所以无法基于这个结果判断是否为普通对象
// instanceof检测机制:验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为true
function Fn() {}
Fn.prototype = Object.create(Array.prototype);
let f = new Fn; //let f = new Fn(); 测试了这样写也可以
console.log(f instanceof Array); //=>true f其实不是数组,因为它连数组的基本结构都是不具备的
- 使用场景️
它本身不能完成数据类型检测,只是利用它检测某个实例是否属于这个类的特征来完成数据检测。比如检测具体结构函数名
思考:如果子继承了父,这样可能是检测到父的结构函数,由此可以判断是否能引用某个函数
三、constructor
[example].constructor===[class] :检测实例和类关系的,从而检测数据类型
- 返回值:属于返回TRUE,不属于返回FALSE
- 优点:
【1】 实例.constructor一般都等于类.prototype.constructor也就是当前类本身(前提是你的 constructor 并没有被破坏) 【2】 能检测基本数据类型
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
- 局限性:
【1】不能够给当前类的原型进行重定向,否则会造成检测的结果不准确(Object)
【2】不能够给当前实例增加私有属性constructor,也会造成检测的结果不准确(Object)
【3】非常容易被修改,因为JS中的constructor是不被保护的(用户可以自己随便改),这样基于constructor检测的值存在不确定性(但是项目中,基本没有人会改内置类的constructor)
- 使用场景
它本身不能完成数据类型检测,当没有重定向时候,利用他的实例数据类型检测(不能重定向)
可以用来检测自定义类
四、Object.prototype.toString.call()
Object.prototype.toString.call([value]):检测数据类型
({}).toString.call([value])
- 返回值:是一个字符串“[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]"
Object.prototype.toString.call(function A(){}) //"[object Function]"
class B{}
Object.prototype.toString.call(B) //"[object Function]"
Object.prototype.toString.call(class B{}) //"[object Function]"
不能检测出自定义类和函数
- 优点:
专门用来检测数据类型的方法,基本上不存在局限性的数据类型检测方式 基于他可以有效的检测任何数据类型的值
- 局限性:
【1】只能检测内置类,不能检测出自定义类和结构函数
【2】只要是自定义类返回的都是‘[Object Function]’
- 使用场景
此方法是基于JS本身专门进行数据检测的,所以是目前检测数据类型比较好的方法。
内置类都可以用来检测。
function isArray(obj){
if(!Array.isArray){
return Object.prototype.toString.call(o)=='[object Array]';
} else {
return Array.isArray(obj)
}
}
总结
综合以上,可以总结出如下使用场景:
-
检测基本数据类型:typeof
-
可以用来检测自定义类和结构函数:constructor / instanceof
-
检查内置类:Object.prototype.toString.call()
-
实例的原型链:instanceof