文章转自<掘金社区>:https://juejin.cn/post/7018748121656066085
数据类型
谈类型判断之前,还是先来回顾回顾js有哪些类型。
基本数据类型:Undefined、Null、Boolean、Number、String,Symbol,BigInt(symbol和bigint是ES6新增)
引用数据类型 :Object(有包含了Array,function、Date、RegExp等)
了解了数据类型之后,我们再来看看有哪些方法来判断
判断方法
1、typeof
typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。返回的结果用该类型的字符串(全小写字母)形式表示,包括以下 7 种:number、boolean、symbol、string、object、undefined、function 等,来我们上代码看看具体情况。
typeof'';// string 有效 typeof 1;// number 有效 typeof Symbol();// symbol 有效 typeof true;//boolean 有效 typeof undefined;//undefined 有效 typeof null;//object 无效 typeof [] ;//object 无效 typeof new Function();// function 有效 typeof new Date();//object 无效 typeof new RegExp();//object 无效
分析:可以发现,typeof并不能完全准确的判断出数据类型。
基本类型中,null不能被判断出来,会返回Object
引用类型中,只有function能准确判断,其他的应用类型如Array,Date等都不行。
由此看来,typeof更加适用于基本类型的判断,并且如果需求上有对null有要求,更要做好对null的特判。
2、instanceof
这个方法用来判断一个对象是否是某个类的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。
let bool = true; let num = 1; let str = 'abc'; let und= undefined; let nul = null; let arr = [1,2,3,4]; let obj = {name:'xiaoming',age:22}; let fun = function(){console.log('hello')}; let s1 = Symbol(); console.log(bool instanceof Boolean);// false console.log(num instanceof Number);// false console.log(str instanceof String);// false console.log(und instanceof Object);// false console.log(nul instanceof Object);// false console.log(arr instanceof Array);// true console.log(obj instanceof Object);// true console.log(fun instanceof Function);// true console.log(s1 instanceof Symbol);// false
分析:我们可以发现从结果中看出instanceof
不能识别出基本的数据类型 number、boolean、string、undefined、unll、symbol。
可以检测出引用类型,如array、object、function
所以说,instanceof适用于引用类型的判断。但在这里需要特别注意的是: instanceof 检测的是原型 ,也就是说他的判断实质上是通过原型链去查找,比如,A instanceof B,会去A的原型链上查找看是否有B,如果有就返回true,没有就沿着原型链往上找,直到顶。所以我们可以看出来这个能判断出亲属关系,但不一定能确定有多亲,如下实例
var arr = [] console.log(arr instanceof Array) //true console.log(arr instanceof Object) //true console.log(Array instanceof Object) //true
分析:很明显,arr是Array的实例,那为什么又是Object的实例,难道这个方法是错的?当然不是了,我们都知道Array是Object的一种实例对象,可以说,Array就是Object的儿子,而arr又是Array的儿子,有了这层继承关系,再加上instanceof是通过原型链去定位的,因此,instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。
那么又该怎么来准确判断是不是数组(Array)类型呢?别担心,ES5给我们提供了一个接口Array.isArray()来帮助我们判断
var arr = [] console.log(arr.isArray())
3、constructor
如果了解原型和原型链的话,对这个比较清楚。不了解也没有关系后续我会专门写一篇关于原型和原型链的文章。
回归正题。在JS中,当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。不了解原型链可能不太好理解。换句话说,每个实例对象(原型实例)都会有一个__proto__属性,在这个属性下面定义了一个constructor属性里面保存了实例对象的构造函数,构造函数的名称就是实例对象的原型(可以理解为他的父亲),以此可以来判断实例对象的原型
let bool = true; let num = 1; let str = 'abc'; let und= undefined; let nul = null; let arr = [1,2,3,4]; let obj = {name:'xiaoming',age:22}; let fun = function(){console.log('hello')}; let s1 = Symbol();console.log(bool.constructor === Boolean);// true console.log(num.constructor === Number);// true console.log(str.constructor === String);// true console.log(arr.constructor === Array);// true console.log(obj.constructor === Object);// true console.log(fun.constructor === Function);// true console.log(s1.constructor === Symbol);//true
但是要注意:null 和 undefined 是无效的对象,对来undefined和null来说是不安全的,因为constructor的指向是可以被改变。因此他们是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。我被坑过,大家小心。
4、toString
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。
let bool = true; let num = 1; let str = 'abc'; let und= undefined; let nul = null; let arr = [1,2,3,4]; let obj = {name:'xiaoming',age:22}; let fun = function(){console.log('hello')}; let s1 = Symbol(); console.log(Object.prototype.toString.call(bool));//[object Boolean] console.log(Object.prototype.toString.call(num));//[object Number] console.log(Object.prototype.toString.call(str));//[object String] console.log(Object.prototype.toString.call(und));//[object Undefined] console.log(Object.prototype.toString.call(nul));//[object Null] console.log(Object.prototype.toString.call(arr));//[object Array] console.log(Object.prototype.toString.call(obj));//[object Object] console.log(Object.prototype.toString.call(fun));//[object Function] console.log(Object.prototype.toString.call(s1)); //[object Symbol]
分析:可能大家在好奇为什么要加上Object.prototype.toString.call,开头已经说toString是Object的原型方法,对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过call / apply来改变this指向再来调用才能返回正确的类型信息。
此方法可以相对较全的判断js的数据类型。但具体用哪个方法还是要看具体场景下的具体需求,一般基本的类型可以选择typeof,引用类型可以使用instanceof。