判斷JS數(shù)據(jù)類型的四種方法

在 ECMAScript 規(guī)范中,共定義了 7 種數(shù)據(jù)類型赖阻,分為 基本類型 和 引用類型 兩大類框杜,如下所示:

基本類型:String浦楣、Number、Boolean霸琴、Symbol椒振、Undefined、Null?

引用類型:Object

基本類型也稱為簡單類型梧乘,由于其占據(jù)空間固定,是簡單的數(shù)據(jù)段庐杨,為了便于提升變量查詢速度选调,將其存儲在棧中,即按值訪問灵份。

引用類型也稱為復(fù)雜類型仁堪,由于其值的大小會改變,所以不能將其存放在棧中填渠,否則會降低變量查詢速度弦聂,因此,其值存儲在堆(heap)中氛什,而存儲在變量處的值莺葫,是一個指針,指向存儲對象的內(nèi)存處枪眉,即按址訪問捺檬。引用類型除 Object 外,還包括 Function 贸铜、Array堡纬、RegExp、Date 等等蒿秦。

鑒于 ECMAScript 是松散類型的烤镐,因此需要有一種手段來檢測給定變量的數(shù)據(jù)類型。對于這個問題棍鳖,JavaScript 也提供了多種方法炮叶,但遺憾的是,不同的方法得到的結(jié)果參差不齊。

下面介紹常用的4種方法悴灵,并對各個方法存在的問題進(jìn)行簡單的分析扛芽。

1、typeof

typeof 是一個操作符积瞒,其右側(cè)跟一個一元表達(dá)式川尖,并返回這個表達(dá)式的數(shù)據(jù)類型。返回的結(jié)果用該類型的字符串(全小寫字母)形式表示茫孔,包括以下 7 種:number叮喳、boolean、symbol缰贝、string馍悟、object、undefined剩晴、function 等锣咒。

typeof'';// string 有效

typeof1;// number 有效

typeofSymbol();// symbol 有效

typeoftrue;//boolean 有效

typeofundefined;//undefined 有效

typeofnull;//object 無效

typeof[] ;//object 無效

typeofnewFunction();// function 有效

typeofnewDate();//object 無效

typeofnewRegExp();//object 無效

有些時候,typeof 操作符會返回一些令人迷惑但技術(shù)上卻正確的值:

對于基本類型赞弥,除 null 以外毅整,均可以返回正確的結(jié)果。

對于引用類型绽左,除 function 以外悼嫉,一律返回 object 類型。

對于 null 拼窥,返回 object 類型戏蔑。

對于 function 返回 ?function 類型。

其中鲁纠,null 有屬于自己的數(shù)據(jù)類型 Null 总棵, 引用類型中的 數(shù)組、日期房交、正則 也都有屬于自己的具體類型彻舰,而 typeof 對于這些類型的處理,只返回了處于其原型鏈最頂端的 Object 類型候味,沒有錯刃唤,但不是我們想要的結(jié)果。

2白群、instanceof

instanceof 是用來判斷 A 是否為 B 的實例尚胞,表達(dá)式為:A instanceof B,如果 A 是 B 的實例帜慢,則返回 true,否則返回 false笼裳。 在這里需要特別注意的是:instanceof 檢測的是原型唯卖,我們用一段偽代碼來模擬其內(nèi)部執(zhí)行過程:

instanceof (A,B) = {

????varL = A.__proto__;

????varR = B.prototype;

????if(L === R) {

????????// A的內(nèi)部屬性 __proto__ 指向 B 的原型對象

????????returntrue;

????}

????returnfalse;

}

從上述過程可以看出,當(dāng) A 的 __proto__ 指向 B 的 prototype 時躬柬,就認(rèn)為 A 就是 B 的實例拜轨,我們再來看幾個例子:

[] instanceof Array;// true

{} instanceof Object;// true

newDate() instanceof Date;// true


function Person(){};

newPerson() instanceof Person;


[] instanceof Object;// true

newDate() instanceof Object;// true

newPerson instanceof Object;// true

我們發(fā)現(xiàn),雖然 instanceof 能夠判斷出 [ ] 是Array的實例允青,但它認(rèn)為 [ ] 也是Object的實例橄碾,為什么呢?

我們來分析一下 [ ]颠锉、Array法牲、Object 三者之間的關(guān)系:

從 instanceof 能夠判斷出 [ ].__proto__ ?指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype琼掠,最終 Object.prototype.__proto__ 指向了null拒垃,標(biāo)志著原型鏈的結(jié)束。因此瓷蛙,[]悼瓮、Array、Object 就在內(nèi)部形成了一條原型鏈:

從原型鏈可以看出速挑,[] 的 __proto__ ?直接指向Array.prototype谤牡,間接指向 Object.prototype,所以按照?instanceof?的判斷規(guī)則姥宝,[] 就是Object的實例。依次類推恐疲,類似的 new Date()腊满、new Person() 也會形成一條對應(yīng)的原型鏈 。因此培己,instanceof 只能用來判斷兩個對象是否屬于實例關(guān)系碳蛋, 而不能判斷一個對象實例具體屬于哪種類型。

instanceof?操作符的問題在于省咨,它假定只有一個全局執(zhí)行環(huán)境肃弟。如果網(wǎng)頁中包含多個框架,那實際上就存在兩個以上不同的全局執(zhí)行環(huán)境零蓉,從而存在兩個以上不同版本的構(gòu)造函數(shù)笤受。如果你從一個框架向另一個框架傳入一個數(shù)組,那么傳入的數(shù)組與在第二個框架中原生創(chuàng)建的數(shù)組分別具有各自不同的構(gòu)造函數(shù)敌蜂。

variframe = document.createElement('iframe');

document.body.appendChild(iframe);

xArray = window.frames[0].Array;

vararr =newxArray(1,2,3);// [1,2,3]

arr instanceof Array;// false

針對數(shù)組的這個問題箩兽,ES5提供了?Array.isArray()方法 。該方法用以確認(rèn)某個對象本身是否為 Array 類型章喉,而不區(qū)分該對象在哪個環(huán)境中創(chuàng)建汗贫。

if(Array.isArray(value)){

???//對數(shù)組執(zhí)行某些操作

}

Array.isArray() 本質(zhì)上檢測的是對象的 [[Class]] 值身坐,[[Class]] 是對象的一個內(nèi)部屬性,里面包含了對象的類型信息落包,其格式為 [object Xxx] 部蛇,Xxx 就是對應(yīng)的具體類型 。對于數(shù)組而言咐蝇,[[Class]] 的值就是 [object Array] 涯鲁。

3、constructor

當(dāng)一個函數(shù) F被定義時嘹害,JS引擎會為F添加 prototype 原型撮竿,然后再在 prototype上添加一個 constructor 屬性,并讓其指向 F 的引用笔呀。如下所示:

當(dāng)執(zhí)行 var f = new F() 時幢踏,F(xiàn) 被當(dāng)成了構(gòu)造函數(shù),f 是F的實例對象许师,此時 F 原型上的 constructor 傳遞到了 f 上房蝉,因此 f.constructor == F

可以看出,F(xiàn) 利用原型對象上的 constructor 引用了自身微渠,當(dāng) F 作為構(gòu)造函數(shù)來創(chuàng)建對象時搭幻,原型上的 constructor 就被遺傳到了新創(chuàng)建的對象上, 從原型鏈角度講逞盆,構(gòu)造函數(shù) F 就是新對象的類型檀蹋。這樣做的意義是,讓新對象在誕生以后云芦,就具有可追溯的數(shù)據(jù)類型俯逾。

同樣,JavaScript 中的內(nèi)置對象在內(nèi)部構(gòu)建時也是這樣做的:

細(xì)節(jié)問題:

1. null 和 undefined 是無效的對象舅逸,因此是不會有 constructor 存在的桌肴,這兩種類型的數(shù)據(jù)需要通過其他方式來判斷。

2. 函數(shù)的 constructor 是不穩(wěn)定的琉历,這個主要體現(xiàn)在自定義對象上坠七,當(dāng)開發(fā)者重寫 prototype 后,原有的 constructor 引用會丟失旗笔,constructor 會默認(rèn)為 Object

為什么變成了 Object彪置?

因為 prototype 被重新賦值的是一個 { }, { } 是 new Object() 的字面量换团,因此 new Object() 會將 Object 原型上的 constructor 傳遞給 { }悉稠,也就是 Object 本身。

因此艘包,為了規(guī)范開發(fā)的猛,在重寫對象原型時一般都需要重新給 constructor 賦值耀盗,以保證對象實例的類型不被篡改。

4卦尊、toString

toString() 是 Object 的原型方法叛拷,調(diào)用該方法,默認(rèn)返回當(dāng)前對象的 [[Class]] 岂却。這是一個內(nèi)部屬性忿薇,其格式為 [object Xxx] ,其中 Xxx 就是對象的類型躏哩。

對于 Object 對象署浩,直接調(diào)用 toString()? 就能返回 [object Object] 。而對于其他對象扫尺,則需要通過 call / apply 來調(diào)用才能返回正確的類型信息筋栋。

Object.prototype.toString.call('') ;??// [object String]

Object.prototype.toString.call(1) ;???// [object Number]

Object.prototype.toString.call(true) ;// [object Boolean]

Object.prototype.toString.call(Symbol());//[object Symbol]

Object.prototype.toString.call(undefined) ;// [object Undefined]

Object.prototype.toString.call(null) ;// [object Null]

Object.prototype.toString.call(newFunction()) ;// [object Function]

Object.prototype.toString.call(newDate()) ;// [object Date]

Object.prototype.toString.call([]) ;// [object Array]

Object.prototype.toString.call(newRegExp()) ;// [object RegExp]

Object.prototype.toString.call(newError()) ;// [object Error]

Object.prototype.toString.call(document) ;// [object HTMLDocument]

Object.prototype.toString.call(window) ;//[object global] window 是全局對象 global 的引用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市正驻,隨后出現(xiàn)的幾起案子弊攘,更是在濱河造成了極大的恐慌,老刑警劉巖姑曙,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件襟交,死亡現(xiàn)場離奇詭異,居然都是意外死亡伤靠,警方通過查閱死者的電腦和手機捣域,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宴合,“玉大人竟宋,你說我怎么就攤上這事⌒畏模” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵徒欣,是天一觀的道長逐样。 經(jīng)常有香客問我,道長打肝,這世上最難降的妖魔是什么脂新? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮粗梭,結(jié)果婚禮上争便,老公的妹妹穿的比我還像新娘。我一直安慰自己断医,他們只是感情好滞乙,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布奏纪。 她就那樣靜靜地躺著,像睡著了一般斩启。 火紅的嫁衣襯著肌膚如雪序调。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天兔簇,我揣著相機與錄音发绢,去河邊找鬼。 笑死垄琐,一個胖子當(dāng)著我的面吹牛边酒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狸窘,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼墩朦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了朦前?” 一聲冷哼從身側(cè)響起介杆,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎韭寸,沒想到半個月后春哨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡恩伺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年赴背,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晶渠。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡凰荚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出褒脯,到底是詐尸還是另有隱情便瑟,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布番川,位于F島的核電站到涂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏颁督。R本人自食惡果不足惜践啄,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沉御。 院中可真熱鬧屿讽,春花似錦、人聲如沸吠裆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至衩婚,卻和暖如春窜护,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背非春。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工柱徙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奇昙。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓护侮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親储耐。 傳聞我的和親對象是個殘疾皇子羊初,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容