JavaScript 資料型別檢測終極解決方案

淘淘笙悅發表於2018-09-19

JavaScript 的資料型別檢測是我們平時開發中經常會遇到的場景,小到基本資料型別大至各種引用資料型別的檢測,都是我們需要掌握的知識點。下文會主要講解 JavaScript 中各種不同資料型別的檢測方法以及最後會實現一個資料型別檢測的終極方法。

紅寶石書告訴我們,JavaScript 中的資料型別有 UndefinedNullBooleanNumberStringObject,其中前五種是基本型別,而 Object 是引用型別。實際上,Object 中還包含了其它更為具體的引用型別,如 ArrayFunctionDateRegExpErrorArguments 等。

在本章的敘述中,我都會以上述 12 種資料型別為基礎來說明不同的檢測方式(實際上 JavaScript 中資料型別不止 12 種,其它資料型別我們鮮少碰到,所以在此就不多做贅述啦)。

我們通常用來檢測資料型別的方法,分別是 typeofObject.prototype.toString,讓我們仔細來看看這兩個方法。

typeof

MDN 中的敘述是,typeof 操作符返回一個字串,表示未經計算的運算元的型別。

其使用方式是 typeof operandtypeof(operand)operand 是一個表示式,表示物件或原始值,其型別將被返回,返回值是表示其資料型別的字串的小寫形式。

那麼讓我們直接來看一下上述的 12 種資料型別使用 typeof 來檢測後返回值分別是什麼:

var und=undefined;
var nul=null;
var boo=true;
var num=1;
var str='xys'
var obj=new Object();
var arr=[1,2,3];
var fun=function(){}
var date=new Date();
var reg = /a/g;
var err=new Error()
var arg;
(function getArg(){
    arg=arguments;
})();

console.log(typeof und);  // undefined
console.log(typeof nul);  // object
console.log(typeof boo);  // boolean
console.log(typeof num);  // number
console.log(typeof str);  // string
console.log(typeof obj);  // object
console.log(typeof arr);  // object
console.log(typeof fun);  // function
console.log(typeof date);  // object
console.log(typeof reg);  // object
console.log(typeof err);  // object
console.log(typeof arg);  // object

複製程式碼

可以看到,使用 typeof 方法來檢測資料型別,基本型別大部分都能被準確檢測並返回正確的字串(除了 Null 型別,其返回 object 字串),而引用型別大部分都不能夠被準確檢測(除了 Function 型別能夠準確返回 function 字串外,其它的都返回了 object 字串)。

由此可得,typeof 方法並不能夠完全精準地檢測出上述 JavaScript 中的 12 中資料型別。

Object.prototype.toString

ES5 規範中是這麼描述 Object.prototype.toString 的:

JavaScript 資料型別檢測終極解決方案

可以知道,Object.prototype.toString 最終會返回形式如 [object class] 的字串,class 指代的是其檢測出的資料型別,這個是我們判斷資料型別的關鍵。

同樣的,讓我們來看下使用 Object.prototype.toString 來檢測上述列舉到的 12 種資料型別都會返回什麼樣的結果:

var toString=Object.prototype.toString;

console.log(toString.call(und));  // [object Undefined]
console.log(toString.call(nul));  // [object Null]
console.log(toString.call(boo));  // [object Boolean]
console.log(toString.call(num));  // [object Number]
console.log(toString.call(str));  // [object String]
console.log(toString.call(obj));  // [object Object]
console.log(toString.call(arr));  // [object Array]
console.log(toString.call(fun));  // [object Function]
console.log(toString.call(date));  // [object Date]
console.log(toString.call(reg));  // [object RegExp]
console.log(toString.call(err));  // [object Error]
console.log(toString.call(arg));  // [object Arguments]

複製程式碼

可以看到,Object.prototype.toString 返回的 [object class] 字串中,class 準確的表示了各個資料的型別,與 typeof 不同的是,class 所代表的資料型別字串首字母是大寫的,而不像 typeof 返回的是小寫字串。

資料型別檢測終極方法

通過上述對兩個檢測資料型別方法的介紹,我們知道 typeof 能夠被用來檢測除 Null 型別外的其它基本型別,並且能夠檢測出引用型別中 Function 資料型別,而 Object.prototype.toString 能夠檢測出所有的資料型別,所以我們可以結合這兩個方法來實現一個 JavaScript 資料型別檢測的終極方法。

/**
 * @desc 資料型別檢測
 * @param obj 待檢測的資料
 * @return {String} 型別字串
 */
function type(obj) {
  return typeof obj !== "object" ? typeof obj : Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

複製程式碼

資料型別的單獨檢測

有時我們希望直接判斷一個資料是否是某個型別,那麼我們可以單獨實現這些判斷某個資料型別的函式,這裡直接給出各個函式的實現程式碼,需要的童鞋可以直接使用。

/**
 * @desc 是否是 Undefined 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isUndefined(obj) {
    return obj === void 0;
}
/**
 * @desc 是否是 Null 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isNull(obj) {
    return obj === null;
}
/**
 * @desc 是否是 Boolean 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isBoolean(obj) {
    return typeof(obj) === 'boolean';
}
/**
 * @desc 是否是 Number 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isNumber(obj) {
    return typeof(obj) === 'number';
}
/**
 * @desc 是否是 String 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isString(obj) {
    return typeof(obj) === 'string';
}
/**
 * @desc 是否是 Object 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
}
/**
 * @desc 是否是 Array 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isArray(obj){
    return Array.isArray?Array.isArray(obj):Object.prototype.toString.call(obj) === '[object Array]';
}
/**
 * @desc 是否是 Function 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isFunction(obj){
    return typeof(obj) === 'function';
}
/**
 * @desc 是否是 Date 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isDate(obj){
    return Object.prototype.toString.call(obj) === '[object Date]';
}
/**
 * @desc 是否是 RegExp 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isRegExp(obj){
    return Object.prototype.toString.call(obj) === '[object RegExp]';
}
/**
 * @desc 是否是 Error 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isError(obj){
    return Object.prototype.toString.call(obj) === '[object Error]';
}
/**
 * @desc 是否是 Arguments 型別檢測
 * @param obj 待檢測的資料
 * @return {Boolean} 布林值
 */
function isArguments(obj){
    return Object.prototype.toString.call(obj) === '[object Arguments]';
}

複製程式碼

相關文章