前言
不论是平时的工作中,还是面试的时候。基本上都会遇到需要判断数据类型的场景。
比如对于后端返回的数据格式是否是我们需要的,
在比如面试的时候,面试官会问到,有哪些方法可以判断数据类型,这些方法有什么区别?等等
这里呢,我就帮大家整理出来了这几种方式?
常见方式
typeof
一般用于基础数据类型
的判断,因为对于引用类型
,typeof 返回的总是object
MDN:
typeof
运算符返回一个字符串,表示操作数的类型。
Demo:
let data1=0;
let data2='';
let data3=false;
let data4=NaN;
let data5=undefined;
let data6=null;
let data7={};
let data8=[];
let data9=function(){};
let data10=Symbol();
console.log(typeof data1) //number
console.log(typeof data2) //string
console.log(typeof data3) //boolean
console.log(typeof data4) //number
console.log(typeof data5) //undefined
console.log(typeof data6) //object
console.log(typeof data7) //object
console.log(typeof data8) //object
console.log(typeof data10) //function
console.log(typeof data11) //symbol
备注:
typeof null 返回object
typeof NaN 返回number
instanceof
通过原型链来实现的方式。
理解原型链的同学都知道,实例对象有个__proto__属性,指向了构造函数的原型。
MDN:
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上
class Dog{
constructor(){
}
}
const dog=new Dog();
console.log(dog instanceof Dog) //true
//instanceof 运算符 左表达式必须是一个实例对象
console.log(true instanceof Boolean) //false
console.log(new Boolean(1) instanceof Boolean) //true
isPrototypeOf
isPrototypeOf()
方法用于测试一个对象是否存在于另一个对象的原型链上。
MDN解释:
备注:
isPrototypeOf()
与instanceof
运算符不同。在表达式 "
object instanceof AFunction
"中,object
的原型链是针对AFunction.prototype
进行检查的,而不是针对AFunction
本身。
代码演示:
function Foo() {}
function Bar() {}
function Baz() {}
Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);
var baz = new Baz();
console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
constructor
原理:实例对象的constructor属性指向创建实例对象的构造函数
代码实现
class Dog{
constructor(){
}
}
const dog=new Dog();
function getConstructorName(val){
return typeof val.constructor==='function'?val.constructor.name:''
}
console.log(getConstructorName(dog)) //"Dog"
注意
由于constructor属性可以被重写,所以建议辅助来使用。
并且不支持null, undefined
Object.prototype.toString
这种方式大家应该不陌生,我们看一些库的源码,会发现很多人都会这么用,或者很多面试文章里都会提到这个。
Object.prototype.toString.call(obj)
可以说是类型检测的高效手段。
原理:
由于JS的原型链特性,所有对象都是继承Object的,所以每个对象都有toString方法,而这个方法都被重写了,返回相对应的函数,和值类型
直接演示代码:
Object.prototype.toString.call([]) //[object Array]
非常用方式
相等比较
简单的来说,就是直接判断是否等于某个特定的值.
比如:
obj === void 0
如果为真,则就可以判断obj是个undefined类型的数据;
一般也用于辅助手段,简化某种特定场景的判断
obj === void 0;
obj === null;
obj === window;
obj === document;
Symbol.toStringTag
这种方式大家基本上都没见过吧。
这是对于前面说的Object.prototype.toString
方式的补充。用于判断自定义数据类型的检查。
Symbol.toStringTag
是一个内置 symbol,它通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签,通常只有内置的Object.prototype.toString()
方法会去读取这个标签并把它包含在自己的返回值里。
看列子:
class Dog{
constructor(){
}
}
const dog=new Dog();
Object.prototype.toString.call(dog) //[object Object]
上面的方式并不能检查出dog是否是Dog实例化的。
基于这种现象,有了这个解决方法.
直接改代码:
class Dog{
constructor(){
}
get [Symbol.toStringTag] (){
return 'Dog'
}
}
const dog=new Dog();
Object.prototype.toString.call(dog) //[object Dog]
鸭子类型
什么叫鸭子类型:
当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
也就是说,我觉得他像什么数据类型,那他就是什么数据类型。
比如我们要判断一个对象是不是Promise对象,
如果这个对象有then,catch方法,那我觉得他就是个Promise;
简单易懂吧。
建议只在自己的代码里使用这个方法。确实很好用。