typeof
instanceof
Object.prototype.toString
只有肯定類型的狀況,才知道當前操做對象擁有哪些功能; 好比使用 push,unshfit,shfit 等方法時,那麼其必須爲數組類型時才能正確使用;javascript
當某些狀況添加類型檢查時,這樣代碼更加健壯,安全;html
返回一個值的數據類型。
基本語法: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
工做原理基於原型鏈,也就是說若是在對象的原型鏈上可以找到構造函數的 prototype 對象,那麼該操做就返回 true;
基本語法:**
object instanceof 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.prototype
和 person.__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 ;
主要引發問題是,由於多個窗口意味着多個全局環境,不一樣的全局環境擁有不一樣的全局對象,從而擁有不一樣的內置類型構造函數.
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 }
默認狀況下(不覆蓋 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
這樣即便要生成其它原生對象驗證函數前面時就簡單多了;