js中對(duì)變量類(lèi)型的判斷

1.通過(guò)typeof可以判斷處幾種基本數(shù)據(jù)類(lèi)型
Boolean,number,string,null,undefined,
但是復(fù)雜數(shù)據(jù)類(lèi)型是分不出來(lái)的,
object分為 Array,function,Date

如果我們?cè)谟?jì)算機(jī)中js中進(jìn)行打印的話,看下例子

console.log(
typeof number /number
typeof string /string
typeof null /object
typeof undefined /undefined
typeof json /object
typeof reg /object

從結(jié)果來(lái)看,arr,json,null,date,reg,等返回的數(shù)據(jù)類(lèi)型是對(duì)象,但是無(wú)法將他們進(jìn)行區(qū)分

typeof是區(qū)分不出Array,json的類(lèi)型的

2.使用instance檢測(cè)(例子)

在js中,判斷一個(gè)變量的類(lèi)型常常用到typeof運(yùn)算符,在使用typpeof運(yùn)算符的時(shí)候采用引用類(lèi)型的存儲(chǔ)值會(huì)出現(xiàn)一個(gè)問(wèn)題,無(wú)論引用什么類(lèi)型的對(duì)象,返回值都是object

instanceof運(yùn)算符與typeof運(yùn)算符相似,用于識(shí)別正在處理的對(duì)象類(lèi)型,與typeof不同的地方是,instanceof方法要求開(kāi)發(fā)者明確的確認(rèn)對(duì)象為某特定類(lèi)型,

function person(){

}
var Tom = new person();
console.log(Tom instanceof person);//ture

function animal{

}
function cat{

}
cat.prototype= new animal();
var Tom = new cat;
console.log(Tom instanceof cat); //ture
console.log(Tom instanceof animal); //ture
所以有詞 可以得出結(jié)論,instanceof 還可以檢測(cè)出多層繼承關(guān)系
好了,我們來(lái)使用instanceof檢測(cè)上面的那些變量:

console.log(
num instanceof Number,
str instanceof String,
bool instanceof Boolean,
arr instanceof Array,
json instanceof Object,
func instanceof Function,
und instanceof Object,
nul instanceof Object,
date instanceof Date,
reg instanceof RegExp,
error instanceof Error
)
// num : false
// str : false
// bool : false
// arr : true
// json : true
// func : true
// und : false
// nul : false
// date : true
// reg : true
// error : true

從上面的運(yùn)行結(jié)果我們可以看到,num, str和bool沒(méi)有檢測(cè)出他的類(lèi)型,但是我們使用下面的方式創(chuàng)建num,是可以檢測(cè)出類(lèi)型的:

var num = new Number(123);
var str = new String('abcdef');
var boolean = new Boolean(true);

同時(shí),我們也要看到,und和nul是檢測(cè)的Object類(lèi)型,才輸出的true,因?yàn)閖s中沒(méi)有Undefined和Null的這種全局類(lèi)型,他們und和nul都屬于Object類(lèi)型,因此輸出了true。

  1. 使用constructor檢測(cè)

在使用instanceof檢測(cè)變量類(lèi)型時(shí),我們是檢測(cè)不到number, 'string', bool的類(lèi)型的。因此,我們需要換一種方式來(lái)解決這個(gè)問(wèn)題。

constructor本來(lái)是原型對(duì)象上的屬性,指向構(gòu)造函數(shù)。但是根據(jù)實(shí)例對(duì)象尋找屬性的順序,若實(shí)例對(duì)象上沒(méi)有實(shí)例屬性或方法時(shí),就去原型鏈上尋找,因此,實(shí)例對(duì)象也是能使用constructor屬性的。

我們先來(lái)輸出一下num.constructor的內(nèi)容,即數(shù)字類(lèi)型的變量的構(gòu)造函數(shù)是什么樣子的:

function Number() { [native code] }

我們可以看到它指向了Number的構(gòu)造函數(shù),因此,我們可以使用num.constructor==Number來(lái)判斷num是不是Number類(lèi)型的,其他的變量也類(lèi)似:

function Person(){

}
var Tom = new Person();

// undefined和null沒(méi)有constructor屬性
console.log(
Tom.constructor==Person,
num.constructor==Number,
str.constructor==String,
bool.constructor==Boolean,
arr.constructor==Array,
json.constructor==Object,
func.constructor==Function,
date.constructor==Date,
reg.constructor==RegExp,
error.constructor==Error
);
// 所有結(jié)果均為true

從輸出的結(jié)果我們可以看出,除了undefined和null,其他類(lèi)型的變量均能使用constructor判斷出類(lèi)型。

不過(guò)使用constructor也不是保險(xiǎn)的,因?yàn)閏onstructor屬性是可以被修改的,會(huì)導(dǎo)致檢測(cè)出的結(jié)果不正確,例如:

function Person(){

}
function Student(){

}
Student.prototype = new Person();
var John = new Student();
console.log(John.constructor==Student); // false
console.log(John.constructor==Person); // true

在上面的例子中,Student原型中的constructor被修改為指向到Person,導(dǎo)致檢測(cè)不出實(shí)例對(duì)象John真實(shí)的構(gòu)造函數(shù)。

同時(shí),使用instaceof和construcor,被判斷的array必須是在當(dāng)前頁(yè)面聲明的!比如,一個(gè)頁(yè)面(父頁(yè)面)有一個(gè)框架,框架中引用了一個(gè)頁(yè)面(子頁(yè)面),在子頁(yè)面中聲明了一個(gè)array,并將其賦值給父頁(yè)面的一個(gè)變量,這時(shí)判斷該變量,Array == object.constructor;會(huì)返回false;

原因:

1、array屬于引用型數(shù)據(jù),在傳遞過(guò)程中,僅僅是引用地址的傳遞。
2、每個(gè)頁(yè)面的Array原生對(duì)象所引用的地址是不一樣的,在子頁(yè)面聲明的array,所對(duì)應(yīng)的構(gòu)造函數(shù),是子頁(yè)面的Array對(duì)象;父頁(yè)面來(lái)進(jìn)行判斷,使用的Array并不等于子頁(yè)面的Array;切記,不然很難跟蹤問(wèn)題!

  1. 使用Object.prototype.toString.call

我們先不管這個(gè)是什么,先來(lái)看看他是怎么檢測(cè)變量類(lèi)型的:

console.log(
Object.prototype.toString.call(num),
Object.prototype.toString.call(str),
Object.prototype.toString.call(bool),
Object.prototype.toString.call(arr),
Object.prototype.toString.call(json),
Object.prototype.toString.call(func),
Object.prototype.toString.call(und),
Object.prototype.toString.call(nul),
Object.prototype.toString.call(date),
Object.prototype.toString.call(reg),
Object.prototype.toString.call(error)
);
// '[object Number]' '[object String]' '[object Boolean]' '[object Array]' '[object Object]'
// '[object Function]' '[object Undefined]' '[object Null]' '[object Date]' '[object RegExp]' '[object Error]'

從輸出的結(jié)果來(lái)看,Object.prototype.toString.call(變量)輸出的是一個(gè)字符串,字符串里有一個(gè)數(shù)組,第一個(gè)參數(shù)是Object,第二個(gè)參數(shù)就是這個(gè)變量的類(lèi)型,而且,所有變量的類(lèi)型都檢測(cè)出來(lái)了,我們只需要取出第二個(gè)參數(shù)即可。或者可以使用Object.prototype.toString.call(arr)=="object Array"來(lái)檢測(cè)變量arr是不是數(shù)組。

我們現(xiàn)在再來(lái)看看ECMA里是是怎么定義Object.prototype.toString.call的:

Object.prototype.toString( ) When the toString method is called, the following steps are taken:

  1. Get the [[Class]] property of this object.
  2. Compute a string value by concatenating the three strings “[object “, Result (1), and “]”.
  3. Return Result (2)

上面的規(guī)范定義了Object.prototype.toString的行為:首先,取得對(duì)象的一個(gè)內(nèi)部屬性[[Class]],然后依據(jù)這個(gè)屬性,返回一個(gè)類(lèi)似于”[object Array]“的字符串作為結(jié)果(看過(guò)ECMA標(biāo)準(zhǔn)的應(yīng)該都知道,[[]]用來(lái)表示語(yǔ)言內(nèi)部用到的、外部不可直接訪問(wèn)的屬性,稱(chēng)為“內(nèi)部屬性”)。利用這個(gè)方法,再配合call,我們可以取得任何對(duì)象的內(nèi)部屬性[[Class]],然后把類(lèi)型檢測(cè)轉(zhuǎn)化為字符串比較,以達(dá)到我們的目的。

  1. jquery中$.type的實(shí)現(xiàn)

在jquery中提供了一個(gè)$.type的接口,來(lái)讓我們檢測(cè)變量的類(lèi)型:

console.log(
$.type(num),
$.type(str),
$.type(bool),
$.type(arr),
$.type(json),
$.type(func),
$.type(und),
$.type(nul),
$.type(date),
$.type(reg),
$.type(error)
);
// number string boolean array object function undefined null date regexp error

看到輸出結(jié)果,有沒(méi)有一種熟悉的感覺(jué)?對(duì),他就是上面使用Object.prototype.toString.call(變量)輸出的結(jié)果的第二個(gè)參數(shù)呀。

我們這里先來(lái)對(duì)比一下上面所有方法檢測(cè)出的結(jié)果,橫排是使用的檢測(cè)方法, 豎排是各個(gè)變量:

這樣對(duì)比一下,就更能看到各個(gè)方法之間的區(qū)別了,而且Object.prototype.toString.call 和 $type 輸出的結(jié)果真的很像。我們來(lái)看看jquery(2.1.2版本)內(nèi)部是怎么實(shí)現(xiàn)$.type方法的:
// 實(shí)例對(duì)象是能直接使用原型鏈上的方法的
var class2type = {};
var toString = class2type.toString;

// 省略部分代碼...

type: function( obj ) {
if ( obj == null ) {
return obj + "";
}
// Support: Android<4.0, iOS<6 (functionish RegExp)
return (typeof obj === "object" || typeof obj === "function") ?
(class2type[ toString.call(obj) ] || "object") :
typeof obj;
},

// 省略部分代碼...

// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

我們先來(lái)看看jQuery.each的這部分:

// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

//循環(huán)之后,class2type的值是:
class2type = {
'[object Boolean]' : 'boolean',
'[object Number]' : 'number',
'[object String]' : 'string',
'[object Function]': 'function',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object RegExp]' : 'regExp',
'[object Object]' : 'object',
'[object Error]' : 'error'
}

再來(lái)看看type方法:

// type的實(shí)現(xiàn)
type: function( obj ) {
// 若傳入的是null或undefined,則直接返回這個(gè)對(duì)象的字符串
// 即若傳入的對(duì)象obj是undefined,則返回"undefined"
if ( obj == null ) {
return obj + "";
}
// Support: Android<4.0, iOS<6 (functionish RegExp)
// 低版本regExp返回function類(lèi)型;高版本已修正,返回object類(lèi)型
// 若使用typeof檢測(cè)出的obj類(lèi)型是object或function,則返回class2type的值,否則返回typeof檢測(cè)的類(lèi)型
return (typeof obj === "object" || typeof obj === "function") ?
(class2type[ toString.call(obj) ] || "object") :
typeof obj;
}

當(dāng)typeof obj === "object" || typeof obj === "function"時(shí),就返回class2type[ toString.call(obj)。到這兒,我們就應(yīng)該明白為什么Object.prototype.toString.call和$.type那么像了吧,其實(shí)jquery中就是用Object.prototype.toString.call實(shí)現(xiàn)的,把'[object Boolean]'類(lèi)型轉(zhuǎn)成'boolean'類(lèi)型并返回。若class2type存儲(chǔ)的沒(méi)有這個(gè)變量的類(lèi)型,那就返回"object"。

除了"object"和"function"類(lèi)型,其他的類(lèi)型則使用typeof進(jìn)行檢測(cè)。即number, string, boolean類(lèi)型的變量,使用typeof即可。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容