咱們在對傳進來的參數作處理以前,確定須要驗證一下是不是咱們想要的,也就是說大多數狀況下,咱們須要對比一下它的類型。html
做者首先給了一個看起來都感受不對的代碼:正則表達式
var Controller = { process: function(items) { if (items !== null) { items.sort(); // 很差的寫法
items.forEach(function(){ // 執行一些邏輯
}); } } };
在這段代碼中,process()方法顯然但願items是一個數組,由於咱們看到items擁有sort()和 forEach()。數組
可是這種寫法有很大的問題:items值能夠是1,也能夠是字符串,甚至能夠是對象,這些值都和null不相等,進而致使後面執行process()會出現問題。因此接下來就是各類檢測:瀏覽器
在JavaScript中有5種原始類型: 字符串、數字、布爾值、undefined和null。若是你想檢測他們,最佳的辦法是使用typeof運算符。(做者推薦: typeof variable這樣的用法,這樣寫也行:typeof(variable),可是看起來像一個函數而不是運算符 )。安全
基本用法:函數
// 檢測字符串
if (typeof name === "string") { anotherName = name.substring(3); } // 檢測數字
if (typeof count === "number") { updateCount(count); } // 檢測布爾值
if (typeof found === "boolean" && "found") { message("Found!"); } // 檢測undefined
if (typeof MyApp === "undefined") { MyApp = { //其餘的代碼
} }
typeof運算符的獨特之處在於,將其用於一個未聲明的變量和值也不會報錯,他們都將經過typeof返回"undefined"。this
最後一個原始值:null。若是咱們所期待的值真的是null,則能夠和null進行比較:spa
// 若是你真的須要檢測null,則使用這種方法
var element = document.getElementById("my-div"); if (element !== null) { element.classname = "found"; }
這裏若是DOM元素不存在,則經過document.getElementById()獲得的是值爲null,這個方法要麼返回一個節點,要麼返回null。因爲這時null是可預見的一種輸出,則可使用!==來檢測返回結果。prototype
運行typeof null 則返回"object", 這是一種低效的判斷null的方法, 若是你須要檢測null,則直接使用恆等運算符(===)或非恆等運算符(!==)。code
引用值也稱做對象(object)。JS中除了原始值以外的值都是引用。有這樣幾種內置的引用函數: Object、Array、Date和Error,數量很少。
typeof運算符在判斷這些引用類型時顯得力不從心,由於全部對象都返回"object"。
檢測某個引用值的類型最好方法是使用instanceof運算符。instanceof的基本語法是:value instanceof constructor。
// 檢測日期
if (value instanceof Date) { console.log(value.getFullYear()); } // 檢測正則表達式
if (value instanceof RegExp) { if (value.test(anotherValue)) { console.log("Mathes"); } } // 檢測Error
if (value instanceof Error) { throw value; }
instanceof的一個頗有意思的特性是它不只檢測構造這個對象的構造器,還檢測原型鏈。由於每一個對象都繼承自Object,所以每一個對象的 value instanceof Object都返回true。
var now = new Date();
console.log(now instanceof Object); // true console.log(now instanceof Date); // true
由於這個緣由, instanceof 來判斷對象是否屬於某個特定類型的作法並不是最佳。
接下來做者談到 :檢測自定義類型最好的作法是使用instanceof運算符。也是惟一的辦法:
function Person(name) { this.name = name; } var me = new Person("Nicholas"); console.log(me instanceof Object); // true
console.log(me instanceof Person); // true
做者後來又補充了一個我沒看懂的限制,在此先記下:
這有個嚴重的限制:假設一個瀏覽器幀(frame A) 裏的一個對象被傳入到另外一個幀(frame B)中。倆個幀裏都定義了構造函數Person。若是來自幀A的對象是幀A的Person的實例,則以下規則成立:
// true frameAPersonInstance instanceof frameAPerson // false frameAPersonInstance instanceof frameBPerson
由於每一個幀(frame)都擁有Person的一份拷貝,它被認爲是該幀中的Person的拷貝的實例,儘管倆個定義可能徹底同樣的。
在最後,做者說明這種問題也出如今其餘倆個很是重要的內置類型:函數和數組。對於他們,通常用不着使用instanceof。
對於檢測函數:最好的方法是使用typeof,由於它能夠跨幀(frame)使用:
function myFunc() { } // 好的寫法
console.log(typeof myFunc === "function"); // true
做者又補充- -(此次是由於IE):用typeof來檢測函數有一個限制。在IE8和更早期的版本的IE瀏覽器中,用時typeof來檢測DOM節點(好比document.getElementById())中的函數都返回"object"而不是"function"。
// IE8及其更早版本的IE
console.log(typeof document.getElementById); // "object"
console.log(typeof document.createElement); // "object"
console.log(typeof document.getElementsByTagName); // "object"
這個問題是早期IE遺留的問題,開發者每每經過in運算符來檢測DOM的方法:
// 檢測DOM方法
if ("querySelectorAll" in document) { images = document.querySelectorAll("img"); }
這段代碼檢查querySelectorAll是否認義在了document中,若是是,則是用這個方法。儘管不是最理想的的方法,若是想在IE8 及更早的瀏覽器中檢測DOM方法是否存在,這是最安全的作法。在其餘全部情形,typeof運算符是檢測JavaScript函數的最佳選擇。
ECMAScript5將Array.isArray()正式引入JavaScript。惟一的目的就是準確的檢測一個值是否爲數組。
適用於(IE9+、Safari五、Opera 10.5+和Chrome)都實現了Array.isArrary()方法。
在此以前,有一個優雅的解決方案:
function isArray(value) { return Object.prototype.toString.call(value) === "[object Array]"; }
將這倆方法合併,多數類庫都相似的實現了這個方法:
function isArray(value) { if (typeof Array.isArray === "function") { return Array.isArray(value); } else { return Object.prototype.toString.call(value) === "[object Array]"; } }
判斷屬性的最好的方法是使用in運算符。in運算符僅僅會簡單地判斷屬性是否存在,而不會去讀屬性的值。
以前第三章也說過:in運算符會遍歷原型鏈。若是你只想遍歷實例對象,用hasOwnProperty()
全部繼承自Object的JavaScript對象都有這個方法。
做者補充到一個例外(又是IE。。醉):在IE8和更早的版本中,DOM對象並不是繼承自Object,所以也不包含這個方法。因此,你在調用DOM對象的hasOwnProperty()方法以前應當先檢測其是否存在(假如你已經知道對象不是DOM。這步能夠省略)。
// 對於全部非DOM對象來講,這是好的寫法
if (object.hasOwnProperty("realted")) { // 執行這裏的代碼
} // 若是你不肯定是否爲DOM對象,則能夠這樣寫
if ("hasOwnProperty" in object && object.hasOwnProperty("related")) { // 執行這裏的代碼
}