javascript判斷數(shù)據(jù)類型

題目

實(shí)現(xiàn)一個函數(shù)typeof(),輸入一個數(shù)據(jù),返回?cái)?shù)據(jù)的基本類型。
如:

typeof([]) => array
typeof({}) => object
typeof("") => string
等等

解析

由于javascript這門語言輝(keng)煌(die)的歷史,所以連這種簡單的需求都需要自己來實(shí)現(xiàn),唉,說多了,都是淚啊。

這兒題目相對來說應(yīng)該是比較簡單的,但是也是有不少坑,想要真正實(shí)現(xiàn)的很好,還是需要用到不少知識的。

一開始,肯定有人想到使用typeof,顧名思義嘛,就是判斷數(shù)據(jù)的類型,但是,可是,實(shí)際真的是這樣嗎?

typeof操作符

typeof 操作符(和 instanceof 一起)或許是 JavaScript 中最大的設(shè)計(jì)缺陷, 因?yàn)閹缀醪豢赡軓乃鼈兡抢锏玫较胍慕Y(jié)果。 --javascript秘密花園

盡管instanceof 還有一些極少數(shù)的應(yīng)用場景,typeof 只有一個實(shí)際的應(yīng)用,就是用來檢測一個對象是否已經(jīng)定義或者是否已經(jīng)賦值,而這個應(yīng)用卻不是用來檢查對象的類型。(好吧,這個其實(shí)貌似也并沒有什么卵用。。。)
在下面表格中,Type 一列表示 typeof 操作符的運(yùn)算結(jié)果。其中,JavaScript 標(biāo)準(zhǔn)文檔中定義: [[Class]] 的值只可能是下面12個字符串中的一個: Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String??梢钥吹?,這個值在大多數(shù)情況下都返回 "object"。

Value Class Type
"foo" String string
new String("foo") String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function("") Function function
/abc/g RegExp object (function in Nitro/V8)
new RegExp("meow") RegExp object (function in Nitro/V8)
{} Object object
new Object() Object object
測試為定義變量
typeof foo !== 'undefined'

上面代碼會檢測 foo 是否已經(jīng)定義;如果沒有定義而直接使用會導(dǎo)致 ReferenceError 的異常。 這是 typeof 唯一有用的地方。

instanceof 操作符

剛說完,typeof,肯定又有人想用instanceof,但是,instanceof真的有用嗎?
instanceof 操作符用來比較兩個操作數(shù)的構(gòu)造函數(shù),instanceof 運(yùn)算符與 typeof 運(yùn)算符相似,用于識別正在處理的對象的類型。具體的可以看看這個JavaScript instanceof 運(yùn)算符深入剖析。
因此,instanceof在判斷一個對象是不是一個類的實(shí)例只有在比較自定義的對象時才有意義。 如果用來比較內(nèi)置類型,將會和 typeof 操作符 一樣用處不大。

比較自定義對象

function Foo() {}
function Bar() {}
Bar.prototype = new Foo();

new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true

// 如果僅僅設(shè)置 Bar.prototype 為函數(shù) Foo 本身,而不是 Foo 構(gòu)造函數(shù)的一個實(shí)例。
Bar.prototype = Foo;
new Bar() instanceof Foo; // false

instanceof 比較內(nèi)置類型

但是,不是通過構(gòu)造函數(shù)創(chuàng)建的對象使用instanceof比較,那得到的,可能就不是你想要的結(jié)果。

new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true

'foo' instanceof String; // false
'foo' instanceof Object; // false

注意

還有有一點(diǎn)需要注意,instanceof 用來比較屬于不同 JavaScript 上下文的對象(比如,瀏覽器中不同的文檔結(jié)構(gòu))時將會出錯, 因?yàn)樗鼈兊臉?gòu)造函數(shù)不會是同一個對象。

看到這里,是不是很震驚?你所知道的知道的方法,都是錯的。。。唉,當(dāng)初我知道了這個也是淚流滿面啊。。。

解決方法

Object.prototype.toString

javascript對象的內(nèi)部屬性 [[Class]] 的值就包含有j其對象的類型,為了獲取對象的 [[Class]],我們需要使用定義在 Object.prototype 上的方法 toString。

function is(type, obj) {
    var clas = Object.prototype.toString.call(obj).slice(8, -1);
    return obj !== undefined && obj !== null && clas === type;
}

is('String', 'test'); // true
is('String', new String('test')); // true

Object.prototype.toString 返回一種標(biāo)準(zhǔn)格式字符串,所以上例可以通過 slice 截取指定位置的字符串,如下所示:

Object.prototype.toString.call([])    // "[object Array]"
Object.prototype.toString.call({})    // "[object Object]"
Object.prototype.toString.call(2)    // "[object Number]"

看看大神的解決方案

如果我沒記錯,在jQueryunderscore等庫中都有判斷數(shù)據(jù)類型的函數(shù),可能平時大家也就用用,沒有仔細(xì)了解過它們的底層是怎么實(shí)現(xiàn)的,

我們要會使用框架,但不要依賴框架

以后大家再碰到類似的問題的時候,不妨查看一下這些成熟框架或庫的實(shí)現(xiàn)源碼,這里,我拋出jQuery的實(shí)現(xiàn)源碼,拋磚引玉。

var class2type = {} ;
"Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach(function(e,i){
    class2type[ "[object " + e + "]" ] = e.toLowerCase();
}) ;
//當(dāng)然為了兼容IE低版本,forEach需要一個polyfill,不作細(xì)談了。
function _typeof(obj){
    if ( obj == null ){
        return String( obj );
    }
    return typeof obj === "object" || typeof obj === "function" ?
    class2type[ Object.prototype.toString.call(obj) ] || "object" :
        typeof obj;
}

結(jié)論:

看源碼是程序員快速成長的重要方式。

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

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

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