Javascript常用见问题之变量类型判断终极篇

类型判断是我们在编程中常遇到的棘手问题,严格的变量类型约束会为代码减少很多致命的BUG。本文是对常用到的类型判断的一个整理,以求以最简洁的方式来判断变量的类型。
本文所有的如果没特指,都是基于ES5的原生javascript

变量的基本类型

JavaScript变量包含两种不同的数据类型的值:基本类型引用类型。基本类型是指简单的数据,有NumberStringBooleanUndefinedNull(null可以算作是一个特殊的基本数据类型),而引用类型指那些可能包含多个值的对象,有ObjectArrayDateRegExpFunction等。在JavaScript中,我们通过var来声明变量,由于JavaScript弱语言类型,我们无法在申明的时候规定他的类型,JavaScript变量的类型是随变量的值改变而改变的。为了代码的安全性,在有些情况下我们要判断变量值的类型,如何正确的判断变量的类型就成了一个比较有深度的问题。下图列举一些常见的类型:

类型 举例
Null null
Undefined undefined、未赋值的变量
Boolean true、false
Number -1、0 、 1、 NaN
String ‘1’、’a’
Array []、new Array()
Object {}、new Object()
Function function(){}

判断他们的类型,第一时间可能你会想到用typeof去检测它们的类型,然后你就崩溃了:明明是Null为什么结果却是oject,明明是Array为什么还是obejct?…因此可以看出typeof方法不是很可靠,我们必须寻找一种行之有效的方法来解决这个问题?请继续往下读(为了方便阅读,下文中所有的para表示要判断的变量):

  • isNaN(para)
  • !para
  • typeof para
  • Object.prototype.toString.call(para);

除了上面这些方法,未来可能会有更多方法来增强变量的约束和判断,比如isNumber

isNaN(para)

用来判断是否为number类型的专有方法。但是需要注意的是,如果使用typeof判断那么结果会是number

!para

常用来判断一个变量是否存在,面对ArryObject引用类型变量时无论是否为空都会被转换成true

typeof para

事实证明typeof并不是万能的,在对除Null以外的基本类型变量是相当有威力的,但是对引用类型变量Null时都会被识别成object,但是请注意:

1
2
typeof {}; //object
typeof Object; //Function

为什么会出现这样的情况呢?因为Object是一个构造函数,而不是object数据类型对象,同理ArrayDateFunction等都是属于构造函数

Object.prototype.toString.call(para)

前面的typeof死在半路,无法打探到引用类型变量null的真实情报,但是我们得出了另一个情报:**他们都是obejct**。别慌,我们另外一个强大的武器,可以直指要害,Object.prototype.toString.call(para)

判断结果比较表

类型 isNaN(para) !para typeof para toString(para)
Null null true true obejct [obejct Null]
Undefined undefined true true undefined [obejct Undefined]
Boolean true/false true false/true true [obejct Boolean]
Number -1 false false number [obejct Number]
Number 0 false true number [obejct Number]
Number 1 false false number [obejct Number]
Number NaN true true number [obejct Number]
String ‘1’ false false string [obejct String]
String ‘a’ true false string [obejct String]
String ‘’ true true string [obejct String]
String ‘ ‘(中间包含空格) true false string [obejct String]
Array []/[4] true false obejct [obejct Array]
Object {}/{n:4} true false obejct [obejct Object]
Function function(){} true false obejct [obejct Function]

总结方法

根据上面的表格对比,我整理了一些常见的方法。并且再比较结果精准的情况下尽可能的简化比较过程.

判断数字(非严格)

字符串’1‘会被识别成number

1
2
3
function isNumber(para){
return !isNaN(para);
};

判断数字(严格)

在必要的情况下使用:此方法会把字符串’1‘识别成string类型

1
2
3
function isStrictNumber(para){
return !isNaN(para) && typeof para === 'number';
};

判断字符串(非严格)

1
2
3
function isString(para){
return typeof para === 'string';
};

判断字符串(严格)

在必要的情况下使用:此种方法会把字符串’1‘识别成number类型

1
2
3
function isStrictString(para){
return isNaN(para) && typeof para === 'string';
};

判断一般数据类型(即非引用类型)

注意:使用typeof判断null结果为object

1
2
3
function isBasicType(para){
return typeof para !== 'obejct';
};

判断是否为null(不能识别’’)

此方法只能识别null,如果要包含’’,请结合方法isStringNull()一起使用

1
2
3
function isNull(para){
return !para && typeof para === 'object';
};

判断是否为空字符串(不包含空格)

此方法只能识别'',如果要包含null,请结合方法isNull()一起使用

1
2
3
function isStringtNull(para){
return !para && typeof para === 'string';
};

判断是否为undefined

1
2
3
function isUndefined(para){
return typeof para === 'undefined';
};

判断是否为false

当为null,undefined,'',0,-0,false,NaN

1
2
3
function isFalse(para){
return !para;
};

判断对象(非严格1–所有的obejct对象)

1
2
3
function isAllObject(_v){
return typeof _v === 'obejct';
};

判断对象(非严格2–除去null的所有object对象)<–> 判断引用类型

1
2
3
function isObject(_v){
return !!v && typeof _v === 'obejct';
};

判断对象(严格–只识别{}JSON对象)

1
2
3
function isStrictObject(_v){
return Object.prototype.toString.call(_v) === '[object Object]';
};

判断数组

1
2
3
function isArray(para){
return Object.prototype.toString.call(para) === '[object Array]';
};

判断对象

这里特指{}类JSON对象

1
2
3
function isObject(para){
return Object.prototype.toString.call(para) === '[object Object]';
};

判断可执行函数

1
2
3
function isFunction(para){
return typeof para === 'function';
};

总结

当我们需要判断其他类型时,完全可以参照上面的表来写出自己的方法哦。
当然现在前端各种流行库不断推陈出新,我们完全可以直接使用别人封装好的库来实现这些功能,比如underscore.jslodash.js等,但是编码的乐趣不就是在于自己解决最本质的问题么。所以即使有这么多的流行库大行其道,也不妨碍我们了解这些知识的初心,说不定哪天你自己也写出一个很火的库呢~
当然随着ES6标准的不断被各大浏览器厂商支持,ES6的普及度越来越广,这些方法都会被内置到原生javascript内部吧(有些方法已经加进去了~)。