JavaScript溫故而知新——類型判斷

typeof

typeof 操做符返回一個字符串,表示未經計算的操做數的類型。node

ES6以前,JavaScript共六種數據類型:Undefined、Null、Boolean、Number、String、Object。使用 typeof 進行類型檢測能夠看到:數組

console.log(typeof 1);                  // number
console.log(typeof 'a');                // string
console.log(typeof true);               // boolean
console.log(typeof undefined);          // undefined
console.log(typeof function fn(){});    // function
console.log(typeof {});                 // object
console.log(typeof null);               // object
console.log(typeof []);                 // object
console.log(typeof new Error());        // object
複製代碼

typeof 只能區分"number", "string", "boolean", "undefined", "function", "object"這六種類型。而且對於 Null 和 Object類型,使用 typeof 都會統一返回 「object」 字符串。bash

要區分 Object 下更多細分的類型,則要用到更加精確的類型判斷方法。閉包

Object.prototype.toString

調用 Object.prototype.toString 會返回一個由 "[object " 和 class 和 "]" 組成的字符串,而 class 是要判斷的對象的內部屬性。來嘗試使用這個方法:app

var number = 1;             // [object Number]
var string = '123';         // [object String]
var boolean = true;         // [object Boolean]
var und = undefined;        // [object Undefined]
var nul = null;             // [object Null]
var obj = {a: 1}            // [object Object]
var array = [1, 2, 3];      // [object Array]
var date = new Date();      // [object Date]
var error = new Error();    // [object Error]
var reg = /a/g;             // [object RegExp]
var func = function a(){};  // [object Function]

function checkType() {
    for (var i = 0; i < arguments.length; i++) {
        console.log(Object.prototype.toString.call(arguments[i]))
    }
}

checkType(number, string, boolean, und, nul, obj, array, date, error, reg, func)
複製代碼

能夠看到不一樣對象類型調用 Object.prototype.toString 的返回結果都是不一樣,而且這個結果重點體如今 class 屬性的不一樣。結合 typeof 和 Object.prototype.toString,咱們能夠封裝一個可以檢測各類數據類型的方法。函數

typeof 和 Object.prototype.toString 的結合使用

var class2type = {};

// 生成class2type映射
"Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
    class2type["[object " + item + "]"] = item.toLowerCase();
})

function type(obj) {
    // IE6中,null 和 undefined會被 Object.prototype.toString 識別成 [object Object]
    if (obj == null) {
        return obj + "";
    }
    // 若是是基本類型,就使用 typeof,引用類型就使用 toString。
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[Object.prototype.toString.call(obj)] || "object" :
        typeof obj;
}
複製代碼

"純對象"的判斷

所謂"純對象",指經過 "{}" 或 "new Object"建立的對象(沒有原型的對象也是一個"純對象")。因爲 "純對象"與其餘對象如null,數組等,使用 typeof 檢測時都會返回 object,所以爲了把 "純對象"區分出來,咱們能夠學習一下jQuery的 isPlainObject 方法post

// 前面寫 type 函數時,用來存放 toString 映射結果的對象
var class2type = {};

// 至關於 Object.prototype.toString
var toString = class2type.toString;

// 至關於 Object.prototype.hasOwnProperty
var hasOwn = class2type.hasOwnProperty;

function isPlainObject(obj) {
    var proto, Ctor;

    // 排除掉明顯不是obj的以及一些宿主對象如Window
    if (!obj || toString.call(obj) !== "[object Object]") {
        return false;
    }

    /**
     * getPrototypeOf es5 方法,獲取 obj 的原型
     * 以 new Object 建立的對象爲例的話
     * obj.__proto__ === Object.prototype
     */
    proto = Object.getPrototypeOf(obj);

    // 沒有原型的對象是純粹的,Object.create(null) 就在這裏返回 true
    if (!proto) {
        return true;
    }

    /**
     * 如下判斷經過 new Object 方式建立的對象
     * 判斷 proto 是否有 constructor 屬性,若是有就讓 Ctor 的值爲 proto.constructor
     * 若是是 Object 函數建立的對象,Ctor 在這裏就等於 Object 構造函數
     */
    Ctor = hasOwn.call(proto, "constructor") && proto.constructor;

    // 在這裏判斷 Ctor 構造函數是否是 Object 構造函數,用於區分自定義構造函數和 Object 構造函數
    ## console.log(hasOwn.toString.call(Ctor)); // function Object() { [native code] }
    ## console.log(Object.prototype.toString.call(Ctor)); // [object Function]
    // hasOwn.toString 調用的實際上是 Function.prototype.toString
    // Function 對象覆蓋了從 Object 繼承來的 Object.prototype.toString 方法,函數的 toString 方法返回表示函數源代碼的字符串
    return typeof Ctor === "function" && hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object);
}
複製代碼

看一下這個方法的使用結果:學習

function Person(name) {
    this.name = name;
}
console.log(isPlainObject({}))                  // true
console.log(isPlainObject(new Object))          // true
console.log(isPlainObject(Object.create(null))) // true
console.log(isPlainObject(Object.create({})))   // false
console.log(isPlainObject(new Person({})))      // false
複製代碼

空對象的判斷

即判斷一個對象是否有屬性ui

function isEmptyObject( obj ) {
        var name;
        // for循環執行,則說明對象有屬性
        for ( name in obj ) {
            return false;
        }
        return true;
}
複製代碼

Window對象

function isWindow( obj ) {
    // Window對象有一個window屬性會指向自身
    return obj != null && obj === obj.window;
}
複製代碼

數組和類數組對象判斷

一樣是jQuery的實現方法this

function isArrayLike(obj) {

    // obj 必須有 length屬性
    var length = !!obj && "length" in obj && obj.length;
    // 引用前面的 type 函數檢測類型
    var typeRes = type(obj);

    // 排除掉函數和 Window 對象
    if (typeRes === "function" || isWindow(obj)) {
        return false;
    }
    // length === 0 是考慮到 arguments 也是一個類數組對象
    // 好比寫一個不傳參數的函數時,arguments的length爲0,但arguments確確實實是一個類數組對象
    return typeRes === "array" || length === 0 ||
        typeof length === "number" && length > 0 && (length - 1) in obj;
}
複製代碼

(length - 1) in obj表示:對象的最後一個元素必須存在。 舉個例子:

var arrLike = {
    2: 3,
    length: 3
}
複製代碼

類數組對象有一個特色是 length 的長度值等於最後一個元素的 key 值加1,假如沒有2: 3這一項的話,那麼類數組對象也就不成立了。

DOM元素的判斷

isElement = function(obj) {
    return !!(obj && obj.nodeType === 1);
};
複製代碼

結尾

系列文章:

相關文章
相關標籤/搜索