原文連接javascript
ES5 中有五種基本(原始)數據類型undefined
,null
,boolean
,number
,string
,ES6 中新增了一種基本數據類型:Symbol
。typeof
是咱們開發中最經常使用的判斷數據類型的JS原生內置運算符,可是有侷限性。java
語法:jquery
typeof運算符後跟操做數:git
typeof ${操做數}
// or
typeof (${操做數})
複製代碼
示例:github
typeof(undefined); // undefined
typeof(null); // object
typeof(true); // boolean
typeof(1); // number
typeof(''); // string
typeof(Symbol(1)); // symbol
typeof(function () {}); // function
typeof([]); // object
typeof({}); // object
typeof(new Date()); // object
typeof(/abc/ig); // object
typeof(Math); // object
typeof(new Error('error')); // object
複製代碼
這裏有兩點須要注意的:函數
typeof null
將返回object
。由於在 JS 的最第一版本中,使用的是 32 位系統,爲了性能考慮使用低位存儲了變量的類型信息,000 開頭表明是對象,然而 null 表示爲全零,因此將它錯誤的判斷爲 object,而後被 ECMAScript 沿用了 。typeof
不能準確判別對象類型到底是什麼具體對象。例如typeof {}
,typeof new Date()
, typeof /abc/ig
,typeof Math
,都是返回object
,有沒有可能告訴咱們這是一個date
對象,那是一個regexp
對象呢?。還有一個不能忍受的是,typeof []
也是返回object
。不少時候,咱們業務中但願能準確區分是array
仍是object
。另外,instanceof
也能夠判斷對象類型,由於內部機制是經過判斷對象的原型鏈中是否是能找到類型的 prototype。可是,並不適用於一些基本數據類型。性能
1 instanceof Number; // false
var num = new Number(1);
num instanceof Number; // true
複製代碼
既然typeof
和instanceof
都有侷限性,那麼有沒有一種相對準確的方法來判斷數據類型呢?答案是確定的,它就是Object.prototype.toString.call(xxx)
方法,其結果返回格式形如:[object Array]
,[object RegExp]
、[object Date]
等。咱們能夠根據其表達式的返回結果中的中括號中的第二個單詞,就能準確判別這個數據的具體類型。網上已有不少資料介紹這個函數的用法,它的表現形式也有不少種:測試
1. Object.prototype.toString.call(xxx);
2. ({}).toString.call(xxx);
3. [].toString.call(xxx);
...
複製代碼
其實,寫法再多也是萬變不離其。都是調用了原型鏈上的原生toString
方法,來爲數據類型作強制類型轉化。ui
若是咱們只須要準確判斷六種基本數據類型,同時又可以準確區分數據類型是function
、array
、仍是object
就足夠的話,那麼咱們能夠這樣實現:spa
var superTypeof = function (val) {
var ans = typeof val;
if (ans === 'object') {
if (val === null) {
ans = 'null';
} else if (Array.isArray(val)) {
ans = 'array';
}
}
return ans;
}
複製代碼
ps: 若是有兼容性要求的同窗,能夠將Array.isArray(val)
語句,改爲val instanceof Array
。
測試
superTypeof(undefined); // undefined
superTypeof(null); // null
superTypeof(true); // boolean
superTypeof(1); // number
superTypeof(''); // string
superTypeof(Symbol(1)); // symbol
superTypeof(function () {}); // function
superTypeof([]); // array
superTypeof({}); // object
superTypeof(new Date()); // object
superTypeof(/abc/ig); // object
superTypeof(Math); // object
superTypeof(new Error('error')); // object
...
複製代碼
某一天,咱們發現,以上的superTypeof
函數,並不能準確告訴咱們,返回的 Object 類型到底是Date
仍是RegExp
仍是其餘比較具體的對象。這個時候,咱們就須要用到上述說起的Object.prototype.toString.call(xxx)
方法了。
var superTypeof = function (val) {
var ans = typeof val;
if (ans === 'object') {
ans = ({}).toString.call(val).slice(8,-1).toLowerCase();
}
return ans;
}
複製代碼
測試:
superTypeof(undefined); // undefined
superTypeof(null); // null
superTypeof(true); // boolean
superTypeof(1); // number
superTypeof(''); // string
superTypeof(Symbol(1)); // symbol
superTypeof(function () {}); // function
superTypeof([]); // array
superTypeof({}); // object
superTypeof(new Date()); // date
superTypeof(/abc/ig); // regexp
superTypeof(Math); // math
superTypeof(new Error('error')); // error
...
複製代碼
經過這種方式,咱們就能準確判斷JS中的數據類型了。
咱們再來看看jquery是怎麼實現相似的功能的:
var class2type = {},
typeStr = "Boolean Number String Function Array Date RegExp Object Error Symbol";
typeStr.split(" ").forEach(function (item) {
class2type[ "[object " + item+ "]" ] = item.toLowerCase();
});
var toType = function (obj) {
if ( obj == null ) {
return obj + "";
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call( obj ) ] || "object" :
typeof obj;
}
複製代碼
是否是以爲大同小異的實現方式,甚至還不夠我寫得優雅呢?其實否則,這有jQuery做者的用意。
最後,我想安利一個有相似功能,且強大精簡的庫typeof2。