近乎完美判断JS数据类型是否可行?或抄袭,如需转载,请联系作者授权本文。本文由作者妹妹LazyCurry创作,收录在作者技术文章栏目前言中。它只是一个名称,用于在特定时间保存特定值。变量的值及其数据类型可以在声明周期内更改。JS的数据类型可以分为基本类型和引用类型。首先我们简单介绍一下这两种数据类型,然后分析几种判断数据类型的方法。当然这也是大公司经常考的面试题。同学们可以根据文章的思路进行回答和拓展,让面试官耳目一新。数据类型基本类型基本类型包括Undefined、Null、String、Number、Boolean和Symbol。原始类型是按值访问的,因此我们可以操作存储在变量中的实际值。基本类型的值在内存中占据固定大小的空间,存放在栈内存中。将原始类型的值从一个变量复制到另一个变量会创建该值的副本,并且这两个值完全独立地存储在堆栈内存中。引用类型引用类型是对象类型,包括Object、Array、Function、Data、Regexp和Error。引用类型的值是存储在堆内存中的对象。JS不允许直接访问内存中的位置,也就是说不能直接访问操作对象的内存空间。在操作一个对象的时候,我们实际上是在操作这个对象的引用,所以引用类型的值是通过引用来访问的。因此[1,2]===[1,2]为假。判断数据类型简单说完了JS的两种数据类型,接下来介绍JS判断数据类型的4种方法。typeoftypeof是确定变量是字符串、数字、布尔值、符号(新ES6类型)还是未定义的最佳工具。请注意,此处未提及null和参考数据。typeof可能返回以下结果之一,结果对应的值如下:undefined:未定义值string:字符串number:数值boolean:布尔符号:唯一值object:对象或空值(null)函数:函数类型未定义;//undefinedtypeofnull;//objecttypeof"这是一个字符串";//字符串类型1;//数字类型为真;//booleantypeofnewSymbol();//symboltypeofnewObject();//newFunction()的对象类型;//functiontypeofnewDate();//object在上面的例子中,对于基本类型,可以返回正确的结果,除了null。调用typeofnull会返回object,因为null被认为是空对象引用,所以返回object。当然,这也是早期JS设计语言遗留下来的bug。在其他引用类型中,除了function,都是返回对象类型,所以不宜使用typeof来判断引用类型数据的类型。typeof适用于判断基本类型值。instanceofinstanceof可以用来判断一个实例对象是否属于某个构造函数,表达式AinstanceofB,如果A是B的实例,则返回true,否则返回false。实现原理其实就是找A的原型链上是否有等于B.prototype的原型。.prototype,则可以返回false。原型链的知识可以参考之前的文章《来自原形与原型链的拷问》复习,这里不再是原型链了~newDate()instanceofDate;//truenewDate()instanceofObject;//true[]instanceof数组;//true[]instanceof对象;//真函数Person(){};constperson=newPerson();人物实例;//真人实例对象;//true从上面的例子可以看出,instanceof可以判断[]是Array的实例,Date对象是Date的实例,person是Person构造函数的实例。这里没有问题,但是instanceof认为这些也是Object的实例,有点迷惑。其实可以根据instanceof的实现原理来分析。实现原理上面已经讲过了。这里我们应用了instanceof的过程来进行数组判断。[]instanceofArray,因为可以找到[].__proto__指向Array.prototype,所以返回true。[]instanceofObject,这里也是沿着[]的原型链找,有[].__proto__指向Array.prototype,因为Array.prototype默认是Object的实例,所以有Array.prototype。__proto__指向Object.prototype,所以instanceof认为[]也是Object的实例。instanceof只能用来判断两个对象是否属于一个实例关系,不能判断一个对象属于什么类型。简单的说就是判断两个类是否从属。instanceof的问题是,如果只有一个全局执行环境,如果网页中有两个frame,实际上是两个不同的全局执行环境,所以Array构造函数有两个不同版本。如果一个数组从一个框架传递到另一个框架,那么传入的数组是一个不同于在第二个框架中本地创建的数组的构造函数。constiframe=document.createElement("iframe");document.body.appendChild(iframe);constIArray=window.frames[0].Array;constiarr=newIArray();iarrinstanceofArray;//falseArray.isArray(iarr);//true为了解决这个问题,ES5增加了Array.isArray(),可以判断一个值是数组还是类数组。在上面提到的原型链中,原型对象的constructor属性指向构造函数,而由于实例对象的__proto__属性指向原型对象,所以可以有:每个实例对象都可以通过构造函数访问其构造函数.而JS内置对象在内部构建时也是这样做的,所以可以用来判断数据类型。"".__proto__.constructor===字符串;//true//去掉下面的属性__proto__,效果一样"".constructor===String;//truenewNumber(1).constructor===Number;//truetrue.constructor===Boolean;//true[].constructor===数组;//truenewDate().constructor===Date;//truenewFunction().constructor===Function;//true可以看出大部分类型都可以通过这个属性来判断。但是,由于undefined和null是无效对象,没有constructor属性,不能这样判断这两个值。另外,当原型被改写时,原型原来的构造函数会丢失,此时判断不会生效。functionPerson(){};Person.prototype={name:"XX"};constperson=newPerson();person.constructor===Person;//false此时打印person.constructor,可以看出是一个Object。为什么会变成Object?这是因为在重定义原型时,传入了一个对象{},而{}是newObject()的字面量值,所以Object原型上的构造函数会传给{},所以person.constructor也会打印出对象。因此,在重写原型对象时,需要对构造函数重新赋值,以保证对象实例的类型不变。记得在开发的时候注意这一点!toStringObject.prototype.toString方法返回对象的类型字符串,因此可用于确定值的类型。因为实例对象可能会自定义toString方法,重写Object.prototype.toString,所以最好在使用的时候加上call。会有以下返回值:[objectUndefined]:未定义值[objectNull]:空值[objectString]:String[objectNumber]:Value[objectBoolean]:Boolean[objectSymbol]:唯一值[objectObject]:object[objectArray]:array[objectFunction]:function[objectDate]:date[objectRegExp]:regular[objectError]:errorObject.prototype.toString.call(undefined);//[对象未定义]Object.prototype.toString.call(null);//[objectNull]Object.prototype.toString.call("这是一个字符串");//[对象字符串]Object.prototype.toString.call(1);//[对象编号]Object.prototype.toString.call(true);//[对象布尔]Object.prototype.toString.call({});//[object对象]Object.prototype.toString.call([]);//[对象数组]Object.prototype.toString.call(newFunction());//[对象函数]Object.prototype.toString.call(newDate());//[对象日期]Object.prototype.toString.call(newRegExp());//[objectRegExp]Object.prototype.toString.call(newError());//[objectError]总结比较typeof好用,但只适用于判断数据的基本类型instanceof可以判断引用类型,但不能检测基本类型,不能跨iframe使用构造函数可以判断所有类型,除了null和undefined,但是构造函数容易修改,toString不能跨iframe使用判断所有类型,所以可以封装成一个万能的DataType()判断所有数据类型函数DataType(tgt,类型){constdataType=Object.prototype.toString.call(tgt).replace(/\[object(\w+)\]/,"$1").toLowerCase();返回类型?数据类型===类型:数据类型;}数据类型(“年轻”);//"字符串"DataType(20190214);//"数字"DataType(true);//“布尔值”DataType([],“数组”);//trueDataType({},"数组");//false总结一下,JS的四种判断方式各有优缺点。如果要根据具体情况采取合适的判断方法,那么到此为止。如果有什么不对的地方,请指出。有你们的支持,我会继续写出更好的文章~结语??关注+点赞+收藏+评论+转发??,原创不易,鼓励作者创作更多优质文章,关注前端公众号IQ,一本专注于CSS/JS开发技巧的前端公众号,更多前端小干货等着你。关注回复免费领取学习资料。关注和回复群拉你进技术交流群。攻略只发在公众号
