實現一個函數typeof(),輸入一個數據,返回數據的基本類型。
如:javascript
typeof([]) => array typeof({}) => object typeof("") => string 等等
因爲javascript這門語言輝(keng)煌(die)的歷史,因此連這種簡單的需求都須要本身來實現,唉,說多了,都是淚啊。java
這兒題目相對來講應該是比較簡單的,可是也是有很多坑,想要真正實現的很好,仍是須要用到很多知識的。程序員
一開始,確定有人想到使用typeof
,顧名思義嘛,就是判斷數據的類型,可是,但是,實際真的是這樣嗎?web
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 惟一有用
的地方。測試
剛說完,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比較,那獲得的,可能就不是你想要的結果。設計
new String('foo') instanceof String; // true new String('foo') instanceof Object; // true 'foo' instanceof String; // false 'foo' instanceof Object; // false
還有有一點須要注意,instanceof 用來比較屬於不一樣 JavaScript 上下文的對象(好比,瀏覽器中不一樣的文檔結構)時將會出錯, 由於它們的構造函數不會是同一個對象。
看到這裏,是否是很震驚?你所知道的知道的方法,都是錯的。。。唉,當初我知道了這個也是淚流滿面啊。。。
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]"
若是我沒記錯,在jQuery
和underscore
等庫中都有判斷數據類型的函數,可能平時你們也就用用,沒有仔細瞭解過它們的底層是怎麼實現的,
咱們要會使用框架,但不要依賴框架
之後你們再碰到相似的問題的時候,不妨查看一下這些成熟框架或庫的實現源碼,這裏,我拋出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; }
看源碼是程序員快速成長的重要方式。