javascript判斷數據類型

題目

實現一個函數typeof(),輸入一個數據,返回數據的基本類型。
如:javascript

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

解析

因爲javascript這門語言輝(keng)煌(die)的歷史,因此連這種簡單的需求都須要本身來實現,唉,說多了,都是淚啊。java

這兒題目相對來講應該是比較簡單的,可是也是有很多坑,想要真正實現的很好,仍是須要用到很多知識的。程序員

一開始,確定有人想到使用typeof,顧名思義嘛,就是判斷數據的類型,可是,但是,實際真的是這樣嗎?web

typeof操做符

typeof 操做符(和 instanceof 一塊兒)或許是 JavaScript 中最大的設計缺陷, 由於幾乎不可能從它們那裏獲得想要的結果。 --javascript祕密花園瀏覽器

儘管instanceof 還有一些極少數的應用場景,typeof 只有一個實際的應用,就是用來檢測一個對象是否已經定義或者是否已經賦值,而這個應用卻不是用來檢查對象的類型。(好吧,這個其實貌似也並無什麼卵用。。。)
在下面表格中,Type 一列表示 typeof 操做符的運算結果。其中,JavaScript 標準文檔中定義: [[Class]] 的值只多是下面12個字符串中的一個: Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String。能夠看到,這個值在大多數狀況下都返回 "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 是否已經定義;若是沒有定義而直接使用會致使 ReferenceError 的異常。 這是 typeof 惟一有用的地方。測試

instanceof 操做符

剛說完,typeof,確定又有人想用instanceof,可是,instanceof真的有用嗎?
instanceof 操做符用來比較兩個操做數的構造函數,instanceof 運算符與 typeof 運算符類似,用於識別正在處理的對象的類型。具體的能夠看看這個JavaScript instanceof 運算符深刻剖析
所以,instanceof在判斷一個對象是否是一個類的實例只有在比較自定義的對象時纔有意義。 若是用來比較內置類型,將會和 typeof 操做符 同樣用處不大。prototype

比較自定義對象

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

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

// 若是僅僅設置 Bar.prototype 爲函數 Foo 自己,而不是 Foo 構造函數的一個實例。
Bar.prototype = Foo;
new Bar() instanceof Foo; // false

instanceof 比較內置類型

可是,不是經過構造函數建立的對象使用instanceof比較,那獲得的,可能就不是你想要的結果。設計

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

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

注意

還有有一點須要注意,instanceof 用來比較屬於不一樣 JavaScript 上下文的對象(好比,瀏覽器中不一樣的文檔結構)時將會出錯, 由於它們的構造函數不會是同一個對象。

看到這裏,是否是很震驚?你所知道的知道的方法,都是錯的。。。唉,當初我知道了這個也是淚流滿面啊。。。

解決方法

Object.prototype.toString

javascript對象的內部屬性 [[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 返回一種標準格式字符串,因此上例能夠經過 slice 截取指定位置的字符串,以下所示:

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

看看大神的解決方案

若是我沒記錯,在jQueryunderscore等庫中都有判斷數據類型的函數,可能平時你們也就用用,沒有仔細瞭解過它們的底層是怎麼實現的,

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

之後你們再碰到相似的問題的時候,不妨查看一下這些成熟框架或庫的實現源碼,這裏,我拋出jQuery的實現源碼,拋磚引玉。

var class2type = {} ;
"Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach(function(e,i){
    class2type[ "[object " + e + "]" ] = e.toLowerCase();
}) ;
//固然爲了兼容IE低版本,forEach須要一個polyfill,不做細談了。
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;
}

結論:

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

相關文章
相關標籤/搜索