《編寫可維護的 JavaScript》讀書筆記第8章:避免“空比較”

想判斷一個變量(或參數)是不是一個數組,顯然不應該只是這樣寫:

if (items != null) { // 不好的寫法
items.sort();
...
}

1. 檢測原始值

5種原始值:字符串、數字、布爾值、null 和 undefined。最佳選擇是使用 typeof 運算符判斷其類型:

  • typeof 字符串 === "string"

  • typeof 數字 === "number"

  • typeof 布爾值 === "number"

  • typeof undefined === "undefined"

2. 檢測引用值

除了原始值之外的值都是引用(也稱作對象)。內置引用類型:Object、Array、Date 和 Error。

使用 instanceof 運算符檢測引用值的類型:vaue instanceof constructor。

示例:

// 檢測日期
if (value instanceof Date) {
console.log(value.getFullYear());
}

// 檢測正則表達式
if (value instanceof RegExp) {
if (value.test(anotherValue)){
console.log("Matches");
}
}

// 檢測 Error
if (value instanceof Error) {
throw value;
}

instanceof 不僅檢測構造對象的構造器,還檢測原型鏈。

var now = new Date();

console.log(now instanceof Object); // true
console.log(now instanceof Date); // true

instanceof 是檢測自定義類型的唯一方法,但是有一個嚴重的限制:不能跨幀(frame)。

假設一個瀏覽器幀(frame A)裏的一個對象被傳入到另一個幀(frame B)中,兩個幀裏都定義了構造函數 Person,如果來自幀A的對象是幀A的Person的實例,那麼:

// true
frameAPersonInstance instanceof frameAPerson

// false
frameAPersonInstance instanceof frameBPerson

這個限制對內置類型——函數和數組也一樣生效。對於這兩個類型來說,一般用不着使用 instanceof。

2.1 檢測函數

JavaScript 中的函數是引用類型,同樣存在 Function 構造函數,每個函數都是它的實例。

function myFunc() {}

// 不好的寫法
console.log(myFunc instanceof Function); // true

應該使用 typeof,會返回“function”:

function myFunc() {}

// 好的寫法
console.log(typeof myFunc === "function"); // true

在 IE 8 和更早版本的 IE 瀏覽器中,使用 typeof 檢測 DOM 節點中的函數都返回“object”而不是“function”。

可以使用 in 運算符來檢測 DOM 的方法:

// 檢測 DOM 方法
if ("querySelectorAll" in document) {
p_w_picpaths = document.querySelectorAll("img");
}
2.2 檢測數組

使用 Douglas Crockford 推薦的“鴨式辨型”(duck typing)檢測:

// 採用鴨式辨型的方法檢測數組
function isArray(value) {
return typeof value.sort === "function";
}

這種檢測方法假定數組是唯一擁有 sort() 方法的對象。如果傳入的參數是一個包含 sort() 方法的對象,也會返回 true。

Juriy Zaytsev 給出了一種優雅的解決方案:

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

該方法被大多數 JavaScript 類庫採納。

對自定義對象不要用這種方法,比如內置 JSON 對象使用這種方法將返回“[object JSON]”。

ECMAScript5 將 Array.isArray() 正式引入 JavaScript,因此很多 JavaScript 類庫都類似地實現了這個方法:

function isArray(value) {
if (typeof Array.isArray === "function") {
return Array.isArray(value);
} else {
return Object.prototype.toString.call(value) === "[object Array]";
}
}

3. 檢測屬性

// 不好的寫法:檢測假值
if (object[propertyName]) {
// 一些代碼
}

// 不好的寫法:和 null 比較
if (object[propertyName] != null) {
// 一些代碼
}

// 不好的寫法:和 undefined 比較
if (object[propertyName] != undefined) {
// 一些代碼
}

最好方法是使用 in 運算符。

var object = {
count: 0,
related: null
};

// 好的寫法
if ("count" in object) {
// 這裏的代碼會執行
}

// 不好的寫法:檢測假值
if (object["count"]) {
// 這裏的代碼不會執行
}

// 好的寫法
if ("related" in object) {
// 這裏的代碼會執行
}

// 不好的寫法:檢測是否爲 null
if (object["related"] != null) {
// 這裏的代碼不會執行
}

使用 hasOwnProperty() 方法檢測屬性是否存在,但在 IE 8 及更早版本中,DOM 對象並非繼承自 Object,因此它們沒有這個方法。

// 對於所有非 DOM 對象來說,這是好的寫法
if (object.hasOwnProperty("related")) {
// 執行這裏的代碼
}

// 如果不確定是否爲 DOM 對象,則這樣寫
if ("hasOwnProperty" in object && object.hasOwnProperty("related")) {
// 執行這裏的代碼
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章