JavaScript 三種方法,能夠肯定一個值究竟是什麼類型

JavaScript 三種方法,能夠肯定一個值究竟是什麼類型。

typeof
instanceof
Object.prototype.toString

爲何須要肯定類型 ?

​ 只有肯定類型的狀況,才知道當前操做對象擁有哪些功能; 好比使用 push,unshfit,shfit 等方法時,那麼其必須爲數組類型時才能正確使用;javascript

​ 當某些狀況添加類型檢查時,這樣代碼更加健壯,安全;html

typeof 運算符

返回一個值的數據類型。

基本語法:java

typeof operand
or
typeof (operand)

operand 是一個表達式,表示對象或原始值,其類型將被返回。括號是可選的.面試

示例:基本數據類型

{

    typeof 1            // "number"
    typeof Number(1)    // "number"
    typeof ''           // "string"
    typeof true         // "boolean"
    typeof null         // "object"
    typeof undefined    // "undefined"
    typeof Symbol       // "function"

}

當操做數(operand)爲基本數據類型,其返回字符串與指望同樣,也可以辨別當前操做數得類型;數組

這裏須要說起下基本數據類型 null ,爲何 typeof null 返回的字符串爲 "object";安全

在 JavaScript 最初的實現中,JavaScript 中的值是由一個表示類型的標籤和實際數據值表示的。對象的類型標籤是 0。因爲 null 表明的是空指針(大多數平臺下值爲 0x00),所以,null的類型標籤也成爲了 0,typeof null就錯誤的返回了"object"函數

示例:引用數據類型

typeof new Number(1)          //  'object'
    typeof new String()         //  'object'
    typeof new Array()          //  'object' 
    typeof new Date()             //  'object'
    
     typeof new Function()       //  'function'

從上面看出,全部經過 new 關鍵實例化的構造函數返回都 object 類型. 固然函數是一個例外;測試

從上述兩個示例能夠看出,當typeof 的操做數爲基本數據類型、函數返回字符串可以區分其數據類型; this

那麼若是須要區分引用類型時須要藉助 JavaScript中另一個運算符;prototype

instanceof 運算符


判斷實例對象是否是類(構造函數)的實例

instanceof 工做原理基於原型鏈,也就是說若是在對象的原型鏈上可以找到構造函數的 prototype 對象,那麼該操做就返回 true;

基本語法:**

object instanceof constructor

參數

  • object
    要檢測的對象.
  • constructor
    某個構造函數

示例一:


let o = new Object();
let bool = new Boolean();
let num = new Number(1);
let str = new String();
let arr = new Array();
// 自定義構造函數
function Person(){} 
function Animal(){} 

let person = new Person();
let animal = new Animal();
person instanceof Person   // true
animal instanceof Animal   // true

o instanceof Object;       // true
bool instanceof Boolean;   // true
num instanceof Number;     // true
str instanceof String;     // true
arr instanceof Array;      // true

這樣彌補 typeof 在檢測引用類型的時的問題;

經過下面的示例,驗證下 instanceof 工做原理:

{
    function Person(){}
    function Animal(){}

    // 例如自定義定義兩個類
    let person = new Person();
    let animal = new Animal();


    console.log(animal instanceof Object);  // =>  true
    console.log(animal instanceof Animal);   // true

    console.log(person instanceof Object); // =>  true
    console.log(person instanceof Person);  // true

    console.log(person instanceof Animal);  // =>  false
    console.log(animal instanceof Person);  // =>  false
}

上面應該跟咱們預期的同樣, 那麼有沒有經過一種辦法讓

person instanceof Animal  // => true

那麼來針對上面做以下調整:

person.__proto__ = Animal.prototype;
console.log(person instanceof Animal) // => true
console.log(person instanceof Person) // => false

嚴格意義上來講, 上述這麼改是沒有意思;這裏只是爲了驗證 instanceof 如何工做的;其次說明 person instanceof Person 返回 true, 則並不意味着給表達式永遠返回 true, Person.prototypeperson.__proto__ 都是可變的;

instanceof 和多個全局對象(多個frame或多個window之間的交互)


能夠定義兩個頁面測試: parent.html、 child.html

//    parent.html

    <iframe src="child.html" onload="test()">
    </iframe>
    <script>
        function test(){
            var value = window.frames[0].v;
            console.log(value instanceof Array); // false
        }
    </script>
//  child.html
    <script>
        window.name = 'child';
        var v = [];
    </script>

嚴格上來講value 就是數組,但parent頁面中打印輸出: false ;也就是 parent 頁面中 Array.prototype != window.frames[0].Array.prototype ;

主要引發問題是,由於多個窗口意味着多個全局環境,不一樣的全局環境擁有不一樣的全局對象,從而擁有不一樣的內置類型構造函數.

instanceof 應用 - 檢測做用域的安全


function Person(name, age){
    this.name = name;
    this.age = age
}

// 正常狀況下
{
    let person = new Person('託尼', 20);
    console.log(person.name,person.age);
}

// 假如在實例化時候忘記添加 new 關鍵字尼? 會出現什麼狀況尼?
{
     let person = Person('託尼', 20);
    console.log(person.name, person.age);  // Uncaught TypeError: Cannot read property 'name' of undefined
    
    // Person 被看成普通的方法執行,其次 name ,age 被添加window上
    console.log(name, age); //=> 託尼 20
}

// 如何避免這樣狀況,在加 new 關鍵字或省略時候都能正常返回實例對象 
{
    function Person(name, age){
        if(this instanceof Person) {
            this.name = name;
            this.age = age
            return this;
        }else {
            return new Person(name, age);
        }
    }
    
    let person = Person('託尼', 20);
    console.log(person.name, person.age);  // 託尼 20
}

Object.prototype.toString 方法


默認狀況下(不覆蓋 toString 方法前提下),任何一個對象調用 Object 原生的 toString 方法都會返回 "[object type]",其中 type 是對象的類型;
每一個類的內部都有一個 [[Class]] 屬性,這個屬性中就指定了上述字符串中的 type(構造函數名) ;

舉個例子吧:

console.log(Object.prototype.toString.call([])); // [object Array]

上述中: Array 對應也就當前對象的 type,一樣就是當前對象的構造函數名;

前面在說 instanceof 在多個做用域的狀況下,嘗試用這種方式解決:

function isArray(arr){
      return Object.prototype.toString.call(arr) === "[object Array]"
  }
  
  console.log(isArray(value)); // true

從輸出來看時完美解決了;

爲何這種方式是能夠咧?這裏辨別類型根據 構造函數名稱,因爲原生數組的構造函數名稱與全局做用域無關,所以使用 toString() 就能保證返回一致的值。

同理其它原生對象檢測也能按照這種方式來,如 Date,RegExp,Function

function isFunction(value) {
        return Object.prototype.toString.call(value) === "[object Function]"
    }
function isDate(value) {
        return Object.prototype.toString.call(value) === "[object Date]"
    }
function isRegExp(value) {
        return Object.prototype.toString.call(value) === "[object RegExp]"
    }

isDate(new Date()); // true
isRegExp(/\w/);        // true
isFunction(function(){}); //true

上述代碼,能夠做進一步改進,因爲 isFunction、isDate、isRegExp 方法中,其實只有 [object ConstructorName] ConstructorName不同,能夠利用工廠函數再修飾一下:

function generator(type){
        return function(value){
            return Object.prototype.toString.call(value) === "[object "+ type +"]"
        }
    }

 let isFunction = generator('Function')
 let isArray = generator('Array');
 let isDate = generator('Date');
 let isRegExp = generator('RegExp');

isArray([]));    // true
isDate(new Date()); // true
isRegExp(/\w/);        // true
isFunction(function(){}); //true

這樣即便要生成其它原生對象驗證函數前面時就簡單多了;

總結:

  • typeof 適用於檢測值類型, 特別注意 null 的問題,這也是面試用常常遇到的.
  • instanceof 檢測引用類型.
  • toString 彌補 instanceof 在跨窗口下對類型檢測問題, toString 只適應於原生對象; 對於用戶自定義的對象沒法區分的.
相關文章
相關標籤/搜索