利用JS判斷數(shù)據(jù)類型的四種方法
前言
Javascript 中的數(shù)據(jù)類型判斷其實(shí)是一個(gè)JavaScript非?;A(chǔ)問(wèn)題,但不論是日常實(shí)際編程過(guò)程中和還是面試時(shí),這都是一個(gè)非常常見(jiàn)的問(wèn)題。
在 ECMAScript 規(guī)范中,共定義了 7 種數(shù)據(jù)類型,分為 基本類型 和 引用類型 兩大類,如下所示:
基本類型:String、Number、Boolean、Symbol、Undefined、Null
引用類型:Object
基本類型也稱為簡(jiǎn)單類型,由于其占據(jù)空間固定,是簡(jiǎn)單的數(shù)據(jù)段,為了便于提升變量查詢速度,將其存儲(chǔ)在棧中,即按值訪問(wèn)。
引用類型也稱為復(fù)雜類型,由于其值的大小會(huì)改變,所以不能將其存放在棧中,否則會(huì)降低變量查詢速度,因此,其值存儲(chǔ)在堆(heap)中,而存儲(chǔ)在變量處的值,是一個(gè)指針,指向存儲(chǔ)對(duì)象的內(nèi)存處,即按址訪問(wèn)。引用類型除 Object 外,還包括 Function 、Array、RegExp、Date 等等。
鑒于 ECMAScript 是松散類型的,因此需要有一種手段來(lái)檢測(cè)給定變量的數(shù)據(jù)類型。對(duì)于這個(gè)問(wèn)題,JavaScript 也提供了多種方法,但遺憾的是,不同的方法得到的結(jié)果參差不齊。
下面介紹常用的4種方法,并對(duì)各個(gè)方法存在的問(wèn)題進(jìn)行簡(jiǎn)單的分析。
1、typeof
typeof 是一個(gè)操作符,其右側(cè)跟一個(gè)一元表達(dá)式,并返回這個(gè)表達(dá)式的數(shù)據(jù)類型。返回的結(jié)果用該類型的字符串(全小寫字母)形式表示,包括以下 7 種:number、boolean、symbol、string、object、undefined、function 等。
typeof''; // string 有效 typeof1; // number 有效 typeofSymbol(); // symbol 有效 typeoftrue; //boolean 有效 typeofundefined; //undefined 有效 typeofnull; //object 無(wú)效 typeof[] ; //object 無(wú)效 typeofnewFunction(); // function 有效 typeofnewDate(); //object 無(wú)效 typeofnewRegExp(); //object 無(wú)效
有些時(shí)候,typeof 操作符會(huì)返回一些令人迷惑但技術(shù)上卻正確的值:
- 對(duì)于基本類型,除 null 以外,均可以返回正確的結(jié)果。
- 對(duì)于引用類型,除 function 以外,一律返回 object 類型。
- 對(duì)于 null ,返回 object 類型。
- 對(duì)于 function 返回 function 類型。
其中,null 有屬于自己的數(shù)據(jù)類型 Null , 引用類型中的 數(shù)組、日期、正則 也都有屬于自己的具體類型,而 typeof 對(duì)于這些類型的處理,只返回了處于其原型鏈最頂端的 Object 類型,沒(méi)有錯(cuò),但不是我們想要的結(jié)果。
2、instanceof
instanceof 是用來(lái)判斷 A 是否為 B 的實(shí)例,表達(dá)式為:A instanceof B,如果 A 是 B 的實(shí)例,則返回 true,否則返回 false。 在這里需要特別注意的是:instanceof 檢測(cè)的是原型,我們用一段偽代碼來(lái)模擬其內(nèi)部執(zhí)行過(guò)程:
instanceof (A,B) = { varL = A.__proto__; varR = B.prototype; if(L === R) { // A的內(nèi)部屬性 __proto__ 指向 B 的原型對(duì)象 returntrue; } returnfalse; }
從上述過(guò)程可以看出,當(dāng) A 的 __proto__ 指向 B 的 prototype 時(shí),就認(rèn)為 A 就是 B 的實(shí)例,我們?cè)賮?lái)看幾個(gè)例子:
[] 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的實(shí)例,但它認(rèn)為 [ ] 也是Object的實(shí)例,為什么呢?
我們來(lái)分析一下 [ ]、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的實(shí)例。依次類推,類似的 new Date()、new Person() 也會(huì)形成一條對(duì)應(yīng)的原型鏈 。因此,instanceof 只能用來(lái)判斷兩個(gè)對(duì)象是否屬于實(shí)例關(guān)系, 而不能判斷一個(gè)對(duì)象實(shí)例具體屬于哪種類型。
instanceof 操作符的問(wèn)題在于,它假定只有一個(gè)全局執(zhí)行環(huán)境。如果網(wǎng)頁(yè)中包含多個(gè)框架,那實(shí)際上就存在兩個(gè)以上不同的全局執(zhí)行環(huán)境,從而存在兩個(gè)以上不同版本的構(gòu)造函數(shù)。如果你從一個(gè)框架向另一個(gè)框架傳入一個(gè)數(shù)組,那么傳入的數(shù)組與在第二個(gè)框架中原生創(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
針對(duì)數(shù)組的這個(gè)問(wèn)題,ES5 提供了 Array.isArray() 方法 。該方法用以確認(rèn)某個(gè)對(duì)象本身是否為 Array 類型,而不區(qū)分該對(duì)象在哪個(gè)環(huán)境中創(chuàng)建。
if(Array.isArray(value)){ //對(duì)數(shù)組執(zhí)行某些操作 }
Array.isArray() 本質(zhì)上檢測(cè)的是對(duì)象的 [[Class]] 值,[[Class]] 是對(duì)象的一個(gè)內(nèi)部屬性,里面包含了對(duì)象的類型信息,其格式為 [object Xxx] ,Xxx 就是對(duì)應(yīng)的具體類型 。對(duì)于數(shù)組而言,[[Class]] 的值就是 [object Array] 。
3、constructor
當(dāng)一個(gè)函數(shù) F被定義時(shí),JS引擎會(huì)為F添加 prototype 原型,然后再在 prototype上添加一個(gè) constructor 屬性,并讓其指向 F 的引用。如下所示:
當(dāng)執(zhí)行 var f = new F() 時(shí),F(xiàn) 被當(dāng)成了構(gòu)造函數(shù),f 是F的實(shí)例對(duì)象,此時(shí) F 原型上的 constructor 傳遞到了 f 上,因此 f.constructor == F
可以看出,F(xiàn) 利用原型對(duì)象上的 constructor 引用了自身,當(dāng) F 作為構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象時(shí),原型上的 constructor 就被遺傳到了新創(chuàng)建的對(duì)象上, 從原型鏈角度講,構(gòu)造函數(shù) F 就是新對(duì)象的類型。這樣做的意義是,讓新對(duì)象在誕生以后,就具有可追溯的數(shù)據(jù)類型。
同樣,JavaScript 中的內(nèi)置對(duì)象在內(nèi)部構(gòu)建時(shí)也是這樣做的:
細(xì)節(jié)問(wèn)題:
1. null 和 undefined 是無(wú)效的對(duì)象,因此是不會(huì)有 constructor 存在的,這兩種類型的數(shù)據(jù)需要通過(guò)其他方式來(lái)判斷。
2. 函數(shù)的 constructor 是不穩(wěn)定的,這個(gè)主要體現(xiàn)在自定義對(duì)象上,當(dāng)開發(fā)者重寫 prototype 后,原有的 constructor 引用會(huì)丟失,constructor 會(huì)默認(rèn)為 Object
為什么變成了 Object?
因?yàn)?prototype 被重新賦值的是一個(gè) { }, { } 是 new Object() 的字面量,因此 new Object() 會(huì)將 Object 原型上的 constructor 傳遞給 { },也就是 Object 本身。
因此,為了規(guī)范開發(fā),在重寫對(duì)象原型時(shí)一般都需要重新給 constructor 賦值,以保證對(duì)象實(shí)例的類型不被篡改。
4、toString
toString() 是 Object 的原型方法,調(diào)用該方法,默認(rèn)返回當(dāng)前對(duì)象的 [[Class]] 。這是一個(gè)內(nèi)部屬性,其格式為 [object Xxx] ,其中 Xxx 就是對(duì)象的類型。
對(duì)于 Object 對(duì)象,直接調(diào)用 toString() 就能返回 [object Object] 。而對(duì)于其他對(duì)象,則需要通過(guò) call / apply 來(lái)調(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 是全局對(duì)象 global 的引用
總結(jié)
到此這篇關(guān)于利用JS判斷數(shù)據(jù)類型的文章就介紹到這了,更多相關(guān)JS判斷數(shù)據(jù)類型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript自然分類法算法實(shí)現(xiàn)代碼
這篇文章介紹了javascript自然分類法算法實(shí)現(xiàn)代碼,有需要的朋友可以參考一下2013-10-10js判斷手機(jī)是否安裝并打開app,未安裝則安裝app【兼容Android、ios,親測(cè)可用】
這篇文章主要介紹了js判斷手機(jī)是否安裝并打開app,未安裝則安裝app,通過(guò)調(diào)用瀏覽器判斷app,兼容Android、ios等系統(tǒng),,需要的朋友可以參考下2023-05-05JavaScript組成、引入、輸出、運(yùn)算符基礎(chǔ)知識(shí)講解
JavaScript 被數(shù)百萬(wàn)計(jì)的網(wǎng)頁(yè)用來(lái)改進(jìn)設(shè)計(jì)、驗(yàn)證表單、檢測(cè)瀏覽器、創(chuàng)建cookies,以及更多的應(yīng)用。這篇文章主要介紹了JavaScript組成、引入、輸出、運(yùn)算符基礎(chǔ)知識(shí)講解,需要的朋友可以參考下2016-12-12canvas實(shí)現(xiàn)簡(jiǎn)易的圓環(huán)進(jìn)度條效果
本文主要分享了canvas實(shí)現(xiàn)簡(jiǎn)易的圓環(huán)進(jìn)度條效果的實(shí)例,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02關(guān)于獲取DIV內(nèi)部?jī)?nèi)容報(bào)錯(cuò)的原因分析及解決辦法
這篇文章主要介紹了關(guān)于獲取DIV內(nèi)部?jī)?nèi)容報(bào)錯(cuò)的原因分析及解決辦法的相關(guān)資料,需要的朋友可以參考下2016-01-01JavaScript中Async/Await通過(guò)同步的方式實(shí)現(xiàn)異步的方法介紹
在JavaScript的異步編程中,我們經(jīng)常使用回調(diào)函數(shù)、Promise和 Async/Await來(lái)解決異步操作的問(wèn)題,Async/Await 又是Promise的語(yǔ)法糖,它的出現(xiàn)讓異步編程變得更加直觀和易于理解,本文將詳細(xì)講解Async/Await如何通過(guò)同步的方式實(shí)現(xiàn)異步2023-06-06輕松實(shí)現(xiàn)jquery手風(fēng)琴效果
這篇文章主要為大家介紹了實(shí)現(xiàn)jquery手風(fēng)琴效果的詳細(xì)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01js實(shí)現(xiàn)iframe框架取值的方法(兼容IE,firefox,chrome等)
這篇文章主要介紹了js實(shí)現(xiàn)iframe框架取值的方法,可兼容IE,firefox,chrome等瀏覽器.涉及JavaScript針對(duì)框架元素取值的相關(guān)技巧,需要的朋友可以參考下2015-11-11