選擇適合的型別判斷方式

Shapeying發表於2018-12-24

型別判斷是個常見問題,有多種不同的判斷方式,每種方式都有適用的場景。

typeof

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

typeof operand 或者 typeof (operand) 都可以,括號為可選的。

型別 結果
Undefined “undefined”
==Null== ==”object”==
Boolean “boolean”
Number “number”
String “string”
Symbol(ECMAScript 6 新增) “symbol”
==函式物件== ==”function”==
任何其他物件 “object”

typeof 會將 nullObject 都返回為 “object”, 這樣就無法區分具體的物件型別(Array , Date , Error等)。

注意:其中函式物件特別返回為”function” 。

    // `number`
    typeof 1
    typeof NaN
    typeof Infinity    
    
    // `string`
    typeof `1`
    
    // `boolean`
    typeof true
    
    // `undefined`
    typeof undefined
    
    // `symbol`
    typeof Symbol(1)
    
    // `object`
    typeof null
    
    // `object`
    typeof {}
    typeof []
    typeof new Date()
    typeof new Number(1)

    // `function`
    typeof function(){}
    typeof class A {}
    typeof Math.sin

instanceof

instanceof運算子用於測試建構函式的prototype屬性是否出現在==物件==的原型鏈中的任何位置

object instanceof constructor

  • 左側引數如果不是物件,將返回false
  • 右側引數如果不是建構函式,將報錯
    let x = 1;
    let y = new Number(1);
    
    x instanceof Number // false   1 不是物件
    y instanceof Number // true  new Number(1)為物件

    // 雖然這種方式測試“x”有原型,但是應該是在獲取的時候,自動進行了物件包裝, 其實獲取的是 new Number(1)
    x.__proto__ === Object.getPrototypeOf(x) === Number.prototype 

    // 沿著原型鏈比對  y.__proto__.__proto__ === Object.prototype , 故返回true
    y instanceof Object // true

instanceof 的判斷結果會隨著物件或者建構函式的改變而不同,而不是固定的值

    class A {}
    class B {}
    let a = new A();

    a instanceof A  // true
    a instanceof B  // false

    // 修改a的 __proto__ 指向
    a.__proto__ = B.prototype

    a instanceof A  // false
    a instanceof B  // true

instanceof不能判斷原始資料型別,但是可以用來判斷物件具體是那種型別


    [] instanceof Array // true
    new Error() instanceof Error // true
    (/[1-9]+/) instanceof RegExp // ture
    new Date() instanceof Date // true

    let x = document.querySelectorAll(`h1`)
    x instanceof NodeList // true
    ···

Object.prototype.toString()

toString()方法返回一個表示該物件的字串。預設情況下,toString()方法被每個Object物件繼承。如果此方法在自定義物件中未被覆蓋,toString() 返回 “[object type]” ,其中type是物件的型別

待檢測物件也許會重寫toString()方法,這時就無法檢測toString來判斷型別。所以要保證能夠檢測型別,需要呼叫Object.prototype.toString來進行判斷。如下:

    let X = function(x) {
        this.name = x
    }

    let x =  new X(); 

    x.toString() // "[object,Object]"  使用繼承的toString
    Object.prototype.toString.call(x) // "[object,Object]"

    X.prototype.toString = function() { // 重寫父類的toString方法
        return `not type`
    }

    x.toString() // "not type"   使用重寫後的toString , 就不再返回型別

    Object.prototype.toString.call(x) // "[object,Object]"

返回的” [ object, Type]” 不好分辨,可以進行特殊的處理,直接返回型別名稱。

    // 獲取型別
    function getType(target){
        let types = {}
        let temp = Object.prototype.toString.call(target)
        //types對映型別
        `Boolean Number String Null Undefined Symbol Function Array Date RegExp Object Error NodeList`.split(` `).map(value => {
            types[`[object ${value}]`] = value.toLowerCase()
        })

        if (types[temp]) {
            return types[temp]
        }else if (temp.indexOf(`HTML`) !== -1) { // 判斷是否為DOM元素
            return `element` 
        }else {
            return
        }
    }
    
    // 測試

    getType(1) //  "number"
    getType(Symbol(1)) // "symbol"
    getType([]) // "array"
    getType({}) // "object"
    getType(document.querySelectorAll(`div`)) // "nodelist"

用如上方法,就可以便捷的獲取到型別名稱了。

其他API

判斷值是否是 NaN Number.isNaN()

Number.isNaN() 判斷值是否是 NaN,和全域性函式 isNaN() 相比,該方法不會強制將引數轉換成數字,只有在引數是真正的數字型別,且值為 NaN 的時候才會返回 true。

    Number.isNaN(NaN);        // true
    Number.isNaN(Number.NaN); // true
    Number.isNaN(0 / 0)       // true
    
    Number.isNaN(null);       // false
    Number.isNaN(37);         // false
    Number.isNaN("37");       // false

    Number.isNaN("NaN");      // false 不會隱式轉換
    window.isNaN(`NaN`)       // true 會隱式轉換

判斷值是否為有窮數 Number.isFinite()

Number.isFinite() 方法用來檢測傳入的引數是否是一個有窮數(finite number)。 和全域性的 isFinite() 函式相比,這個方法不會強制將一個非數值的引數轉換成數值,這就意味著,只有數值型別的值,且是有窮的(finite),才返回 true

    Number.isFinite(Infinity);  // false
    Number.isFinite(NaN);       // false
    Number.isFinite(-Infinity); // false

    Number.isFinite(0);         // true
    Number.isFinite(2e64);      // true

    Number.isFinite(`0`);       // false, 全域性函式 isFinite(`0`) 會返回 true

判斷值是否為整數 Number.isInteger()

Number.isInteger() 方法用來判斷給定的引數是否為整數。

    Number.isInteger(0);         // true
    Number.isInteger(1);         // true
    Number.isInteger(-100000);   // true

    Number.isInteger(0.1);       // false
    Number.isInteger(Math.PI);   // false

    Number.isInteger(Infinity);  // false
    Number.isInteger(-Infinity); // false
    Number.isInteger("10");      // false 不會進行隱式轉換
    Number.isInteger(true);      // false
    Number.isInteger(false);     // false
    Number.isInteger([1]);       // false

相關文章