做者: JowayYoung
仓库: Github、 CodePen
博客: 掘金、 思否、 知乎、 简书、 头条、 CSDN
公众号: IQ前端
联系我:关注公众号后有个人 微信哟
特别声明:原创不易,未经受权不得对此文章进行转载或抄袭,不然按侵权处理,如需转载或开通公众号白名单可联系我,但愿各位尊重原创的知识产权
本文由笔者师妹LazyCurry创做,收录于笔者技术文章专栏下前端
JS的变量与其余语言的变量有很大区别,由于其变量松散的本质,决定了变量只是在特定时间内用于保存特定值的一个名字而已,变量的值及其数据类型可在声明周期内改变。git
JS的数据类型可分为基本类型和引用类型,先简单介绍两种数据类型,再来分析判断数据类型的几种方法。固然,这个也是大厂常考的面试题,同窗们可按照文章的思路进行回答和扩展,让面试官耳目一新。github
基本类型
基本类型包括Undefined、Null、String、Number、Boolean、Symbol
。基本类型按值访问,因此咱们可操做保存在变量中实际的值。面试
基本类型的值在内存中占据固定大小的空间,是被保存在栈内存中。从一个变量向另外一个变量复制基本类型的值,会建立这个值的一个副本,这两个值彻底独立地存放在栈内存中。segmentfault
引用类型
引用类型是对象类型,包括Object、Array、Function、Data、Regexp、Error
。引用类型的值是保存在堆内存中的对象,JS不容许直接访问内存中的位置,也就是说不能直接访问操做对象的内存空间。数组
操做对象时,其实是在操做对象的引用,因此说引用类型的值是按引用访问的。从而有[1, 2] === [1, 2]
为false
。微信
简单的讲完JS的两种数据类型,接下来介绍一下JS判断数据类型的4种方法。app
typeof
typeof是肯定一个变量是string
、number
、boolean
、symbol
(ES6新增类型)仍是undefined
的最佳工具。注意,这里并无说起null
以及引用型数据。框架
typeof可能返回下面某个结果,结果的对应值以下:frontend
null
)typeof undefined; // undefined typeof null; // object typeof "这是一段字符串"; // string typeof 1; // number typeof true; // boolean typeof new Symbol(); // symbol typeof new Object(); // object typeof new Function(); // function typeof new Date(); // object
上面的例子中,对于基本类型来讲,除开null
均可返回正确的结果。调用typeof null
会返回object
,是由于null被认为是一个空的对象引用,所以返回了object,固然这个也是JS设计语言早期遗留的Bug。
而在其余引用类型,除开function
均返回object
类型,所以用typeof来判断引用类型数据的类型并不可取,typeof
适合用来判断基础类型值。
instanceof
instanceof
可用来判断一个实例对象是否属于一个构造函数,其表达式A instanceof B
,若是A是B的实例,则返回true
,不然返回false
。
实现原理其实就是在A的原型链上寻找是否有原型等于B.prototype,若是一直找到A原型链的顶端null,仍然找不到原型等于B.prototype,那么就可返回false
。原型链的知识可戳往期文章《来自原形与原型链的拷问》回顾下哦,这里就再也不讲原型链啦~
new Date() instanceof Date; // true new Date() instanceof Object; // true [] instanceof Array; // true [] instanceof Object; // true function Person() {}; const person = new Person(); person instanceof Person; // true person instanceof Object; // true
从上面的例子可看到,instanceof
可判断出[]
是Array
的实例,Date
对象是Date
的实例,person
是Person构造函数
的实例,到这里并没什么问题,可是instanceof
认为这些也都是Object
的实例,这就有点使人疑惑。
其实可根据instanceof
的实现原理来分析一下,上面已经讲过实现原理,在这里咱们套用一下instanceof
用于数组判断的过程。
[] instanceof Array
,由于能找到[].__proto__
指向Array.prototype
,所以返回true。[] instanceof Object
,在这里就是也是要沿着[]
的原型链找,有[].__proto__
指向Array.prototype
,又由于Array.prototype
默认是Object的实例,因此有Array.prototype.__proto__
指向了Object.prototype
,所以这就是为何instanceof
认为[]
也是Object
的实例。
instanceof
只能用来判断两个对象是否属于实例关系,并不能判断一个对象属于什么类型。简单说,就是判断两个类是否从属关系。
instanceof
的问题在于,假如只有一个全局执行环境,若是网页中有两个框架,实际上就存在两个不用的全局执行环境,从而存在两个不一样版本的Array
构造函数。若是从一个框架向另外一个框架传入一个数组,那么传入的数组与第二个框架中原生建立的数组分别是不一样的构造函数。
const iframe = document.createElement("iframe"); document.body.appendChild(iframe); const IArray = window.frames[0].Array; const iarr = new IArray(); iarr instanceof Array; // false Array.isArray(iarr); // true
为了解决这个问题,ES5新增了Array.isArray()
,这个方法能肯定某个值是否是数组或类数组。
constructor
上面提到的原型链,原型对象的constructor
属性指向了构造函数,又由于实例对象的__proto__
属性指向原型对象,所以可有:每个实例对象均可经过constructor来访问它的构造函数
。而JS内置对象在内部构建时也是这么作的,所以可用来判断数据类型。
"".__proto__.constructor === String; // true // 下面将属性__proto__去掉,效果相同 "".constructor === String; // true new Number(1).constructor === Number; // true true.constructor === Boolean; // true [].constructor === Array; // true new Date().constructor === Date; // true new Function().constructor === Function; // true
可看出,大部分类型都能经过这个属性来判断。可是因为undefined
和null
是无效的对象,所以是没有constructor
属性的,这两个值不能用这种方法判断。另外,当重写原型时,原型原有的constructor
会丢失,这时判断也就不生效了。
function Person() {}; Person.prototype = { name: "XX" }; const person = new Person(); person.constructor === Person; // false
这时打印person.constructor
,可看到是一个Object。为何会变成Object呢?这是由于在从新定义原型时,传入的是一个对象{}
,{}
是new Object()
的字面量,所以会将Object原型上的constructor
传递给{}
,因此person.constructor
也就打印出了Object。
所以,在重写原型对象时,都须要给constructor
从新赋值,来保证对象实例的类型不改变。这个点在开发时记得记得注意!
toString
Object.prototype.toString
方法返回对象的类型字符串,所以可用来判断一个值的类型。由于实例对象有可能会自定义toString方法,会覆盖Object.prototype.toString
,因此在使用时,最好加上call
。会有如下返回值:
[object Undefined]
:未定义的值[object Null]
:空值[object String]
:字符串[object Number]
:数值[object Boolean]
:布尔[object Symbol]
:惟一值[object Object]
:对象[object Array]
:数组[object Function]
:函数[object Date]
:日期[object RegExp]
:正则[object Error]
:错误Object.prototype.toString.call(undefined); // [object Undefined] Object.prototype.toString.call(null); // [object Null] Object.prototype.toString.call("这是字符串"); // [object String] Object.prototype.toString.call(1); // [object Number] Object.prototype.toString.call(true); // [object Boolean] Object.prototype.toString.call({}); // [object Object] Object.prototype.toString.call([]); // [object Array] Object.prototype.toString.call(new Function()); // [object Function] Object.prototype.toString.call(new Date()); // [object Date] Object.prototype.toString.call(new RegExp()); // [object RegExp] Object.prototype.toString.call(new Error()); // [object Error]
总结与对比
typeof
使用简单,可是只适用于判断基础类型数据instanceof
能判断引用类型,不能检测出基本类型,且不能跨iframe使用 constructor
基本能判断全部类型,除了null和undefined,可是constructor容易被修改,也不能跨iframe使用toString
能判断全部类型,所以可将其封装成一个全能的DataType()
判断全部数据类型function DataType(tgt, type) { const dataType = Object.prototype.toString.call(tgt).replace(/\[object (\w+)\]/, "$1").toLowerCase(); return type ? dataType === type : dataType; } DataType("young"); // "string" DataType(20190214); // "number" DataType(true); // "boolean" DataType([], "array"); // true DataType({}, "array"); // false
JS的四种判断方法都有各自的优势跟缺点,要根据具体状况采起合适的判断方式。那么就到这里啦,有什么写得不对还麻烦各位大佬指出。有大家的支持我还会继续写出更好的文章~
❤️关注+点赞+收藏+评论+转发❤️,原创不易,鼓励笔者创做更好的文章
关注公众号IQ前端
,一个专一于CSS/JS开发技巧的前端公众号,更多前端小干货等着你喔
关键词
免费领取视频教程我微信
拉你进技术交流群IQ前端
,更多CSS/JS开发技巧只在公众号推送