JS的基本数据类型有null,undefined,number,string,boolean,object。
一.数据类型的判断
若要判断一个元素的类型,可通过typeof、instanceof、constructor和Object.prototype.toString.call()来判断。
1.typeof
var num=1;
alert(typeof num);//弹出number
var str="aaa";
alert(typeof str);//弹出string
var bool=true;
alert(typeof bool);//弹出boolean
var a;
alert(a);//弹出undefined
var arr=[1,2,3];
alert(typeof arr);//弹出object
var obj={a:1,b:2,c:3};
alert(typeof obj);//弹出object
function Fun1(){}
var fun1=new Fun1()
alert(typeof fun1);//弹出object
function fun2(){}
alert(typeof fun2)//弹出function
var b=null;
alert(typeof null)//弹出object
需要注意的是最后三个。其中倒数第二和第三个同样都是函数,一个弹出object,一个弹出function,那是因为前者是构造函数,fun1是Fun1通过new来得到了一个实例,故是object,后者就是个function了,而最后一个为何会弹出object呢?因为最开始JS是想定义null为一个空引用,可以理解为这是一个历史遗存的bug。
现在的问题是:我可以获取到任一一个元素的类型,但是null、obj和arr怎么判断?JS提供了Array.isArray方法来判断一个object是否为array,比如Array.isArray([]),弹出true。那null呢?所以来说typeof不完美。
2.instanceof
let num = 1;
console.log(num instanceof Number);// 打印false
let str = "abc";
console.log(str instanceof String);//打印false
let bool = true;
console.log(bool instanceof Boolean);//打印false
let arr = [1, 2, 3];
console.log(arr instanceof Array);//打印true
let obj = { a: 1, b: 2 };
console.log(obj instanceof Object);//打印true
let test = function () { };
console.log(test instanceof Function);//打印true
let a;
console.log(a instanceof undefined);//报错
let b = null;
console.log(b instanceof null);//报错
可以看出,JS的基本数据类型是无法通过instanceof来判断的,而引用类型的具体类型是可以被判断出来的,null和undefined直接报错。instanceof看起来也没有那么完美。
3.constructor
let num = 1;
console.log(num.constructor==Number);//打印true
let str = "abc";
console.log(str.constructor==String);//打印true
let bool = true;
console.log(bool.constructor==Boolean);//打印true
let arr = [1, 2, 3];
console.log(arr.constructor==Array);//打印true
let obj = { a: 1, b: 2 };
console.log(obj.constructor==Object);//打印true
let test = function () { };
console.log(test.constructor==Function);//打印true
let a;
console.log(a.constructor==undefined);//报错
let b = null;
console.log(b.constructor==null);//报错
constructor指向的是该对象的构造函数。可以看出constructor除了undefined和null其他都可以判断出来了,但是若改变一个对象的原型指向,那么该方法的弊端就显示出来了。比如说:
function MyFun() { };
var myFun = new MyFun();
console.log(myFun.constructor === MyFun); // 打印true
但是我改变了myFun的原型,如下所示:
function MyFun() { };
function MyFun1() { };
//将MyFun的原型指向new MyFun1()
MyFun.prototype=new MyFun1();
let myFun=new MyFun();
console.log(myFun.constructor === MyFun); // 打印false
console.log(myFun.constructor === MyFun1); // 打印true
所以这个constructor也不是完美的。
4.Object.prototype.toString.call()
let o=Object.prototype.toString;
let num = 1;
console.log(o.call(num));
let str = "abc";
console.log(o.call(str));
let bool = true;
console.log(o.call(bool));
let arr = [1, 2, 3];
console.log(o.call(arr));
let obj = { a: 1, b: 2 };
console.log(o.call(obj));
let test = function () { };
console.log(o.call(test));
let a;
console.log(o.call(a));
let b = null;
console.log(o.call(b));
打印结果如图所示:
可以看出,通过Object.prototype.toString.call()方法可以将所有的类型都精确打印出来,就算改变了对象的原型,照样可以打印出来,只可惜打印的这个是字符串。
总结:typeof可以判断出大致类型,但是不能精确地判断出引用类型,其中typeof null会打印object;instanceof可以精确地判断出引用类型,但是不能判断出基本类型,判断undefined、null会报错;constructor可以判断出基本数据类型和引用类型,但是判断null和undefined会报错,并且改变对象的原型会返回该对象指向的新原型的类型;Object.prototype.toString.call()可以判断出所有的类型,但是返回的是一个字符串。
另外isNaN也可以判断Number,并且NaN==NaN会报错,还有就是null与undefined的区别是什么呢?undefined代表的是没有定义或者是定义了没有赋值;而null代表定义了一个地址为空的对象。
二.数据类型的转换
1.转为string,方法有三,一是toString(),该方法不能转null和undefined;二是String(),该方法什么都可以转为string;三是隐式转换,即当一个string类型的元素与其他相加的时候就会隐式转换为string,undefined和null也可以转,比如alert("a"+undefined)会弹出aundefined。
2.转为number,方法有四。
(1)Number()
var arr=[];
alert(Number(arr))//弹出0
var arr1=[1,2,3]
alert(Number(arr1))//弹出NaN,因为里面有逗号
var str1="";
alert(Number(str1))//弹出0
var str2 = "123"
alert(Number(str2))//弹出123
var str3 = "1A23"
alert(Number(str3))//弹出NaN,因为里面有逗号
var a = null;
alert(Number(a))//弹出0
var bool = false;
alert(Number(bool))//弹出0
var b;
alert(Number(b));//弹出NaN
var obj={};
alert(Number(obj))//弹出NaN
总结:Number只要遇见非数字的就返回NaN,而Number(null)返回0,而Number(false)返回0,而Number([])返回0,Number(undefined)返回NaN。需要注意的是NaN==NaN返回的为false
(2)parseInt()
alert(parseInt(arr))//弹出NaN
var arr1=[1,2,3]
alert(parseInt(arr1))//弹出1
var str1="";
alert(parseInt(str1))//弹出NaN
var str2 = "123"
alert(parseInt(str2))//弹出123
var str3 = "1A23"
alert(parseInt(str3))//弹出1
var a = null;
alert(parseInt(a))//弹出NaN
var bool = false;
alert(parseInt(bool))//弹出NaN
var b;
alert(parseInt(b));//弹出NaN
var obj={};
alert(parseInt(obj))//弹出NaN
总结:parseInt除了string类型其他都转为NaN,string要看头一个元素,若是非数字,也弹出NaN,若是数字,那么就获取到,直到遇见非数字为止。
另外延伸一点JS中对number取整的方法。向上取整:Math.ceil(2.1)返回3;向下取整:Math.floor(2.9)返回2;四舍五入:Math.round(2.6)返回3。
(3)parseFloat()与parseInt类似,只不过前者是转为int类型,后者转为了float类型。
(4)隐式转换。比如alert("12"-"7"),弹出5(类型为number)。这是因为减号在JS中只能用作相减,所以会将字符串隐式转为number再进行相减。而加号在JS的作用除了相加还有就是字符串连接,所以alert("12"+1)的结果是121(类型为string)。
三.数据类型是否相等的判断
1===运算符
(1)若数据类型不同,那么为不等。
(2)若数据类型为null,undefined,number,bollean,那么它们的值相等就判断为相等。
(3)在判断时,若有一个为NaN,那么就不等。
(4)string类型的长度、编码、内容不同都是不等。
(5)object类型的,要看两者是否指向不同对象就为不等。比如arr1=[1,2],arr2=[1,2],arr1===arr2返回的是false。若arr1=[1,2].arr2=arr1,则返回的是true。
2.==运算符
若两个值的类型相同,那么和===的判断规则是一样的,若两者的类型不同,JS会做一个隐式转换,那么就不一定会返回false,规则如下(包含了所有的情况):
(1)object与string比较时,先将object转换为string,再进行比较。比如[1,2,3]=="1,2,3"返回true。
(2)object与number比较时,先将obj转为number,再比较。比如[1]==1,返回true。
(3)obj与boolean比较时,先将obj和bollean都转为number,再比较。比如[]==false,返回true。因为[]转string为"",""转number为0,false转number为0。
(4)string与number比较时,先将string转为number再比较。比如"1"==1,返回true。
(5)string与boolean比较时,先将它们都转为number,再比较.比如"1"==true,返回true,而"2"==true返回false。因为boolean转number的规则是true为1,false为0。
(6)boolean与number比较时,先将boolean转为number,再比较。比如1==true,返回true。
(7)若是undefined与object,string,number,bollean进行比较,那么都返回false。
(8)同样若是null与object,string,number,bollean进行比较,那么都返回false。
(9)需要注意null==undefined返回的是true。
总结:object、number、string、boolean进行对比的时候,只要是两个不同类型的元素比较,那么就将它们都转换为number,除了object和string做对比的时候。当null和undefined与其他四种比较时,全部返回false,而null和undefined比较却返回true。