1. 物件的簡單介紹與一些注意事項
JavaScript中具有幾個簡單資料型別:數字、字串、布林值、null值以及undefined值。除此之外其餘所有值(包括陣列、函式,甚至正規表示式)都是物件。數字、字串以及布林值表面是物件(因為他們具有方法),但它們是不可變的,只是JavaScript在引用某個數字、字串或者布林值時,通過呼叫new Number()、new String()和new Boolean()構造器將其轉換為了數字、字串或布林物件,它自有的方法也是從原型中繼承而得到。基本資料型別不可以被改變,因此在沒有指標再指向它時,它在記憶體中佔用的資源自動被釋放,而物件卻永遠以引用的方式傳遞,改變物件中的值,也就改變了它在記憶體中的值。
注:理論上說,null值就是null值,不應該被檢測為物件,但實際上,由於JavaScript的設計失誤,typeof null === "object"是一個事實。
因此在檢驗null值時,儘量要使用其他方法如:!null === true。例如,要檢測一個剛獲取的DOM物件是否正常獲取到了,我們應該使用如下的程式碼:
1 var element = document.getElementById("elementID"); 2 if(element){} 3 // 或者if(!element){}
而不要使用:
1 var element = document.getElementById("elementID"); 2 if(typeof element !== "object") {} 3 // 或者if(typeof element === "object") {}
上面說到,因為typeof null === "object",這樣下面這段程式碼中,即使element獲取不正常(即值為null)時,if語句也會按照獲取正常的結果辦事。
2. 物件的屬性
物件存在的意義就是它可以有許多的屬性和方法幫助我們表達邏輯。物件的屬性可以為任意的值,可以是數字、字串、布林值、null值,也可以是物件或者是函式(當然函式本質上也是物件)。輸出一個屬性,如果它已經被定義,但是一個null值,就會對應輸出null,如果它甚至還未被定義,就會對應輸出undefined。
我們先用字面量定義一個物件,方便後面的測試:
1 var game = { 2 name: "Mini Warior", 3 id: 201907271234, 4 qualification: { 5 type: "test" 6 } 7 }
我們對物件屬性的操作一般來說就是CURD,最常用的就是修改更新和檢索取值。
修改更新一個物件的屬性,我們可以直接使用賦值語句。而一般檢索並獲取物件的屬性,有兩種方法:第一種,因為更緊湊可讀性更強而最為常用的一種: var gameName = game.name; 我們稱為(這裡有個點↘). 表示法;第二種,就像獲取陣列對應下標的值一樣: var gameName = game["name"]; 。檢索獲取屬性值時,我們也要考慮到屬性不存在的情況,這時候我們可以巧用運算子填充預設值: var gameName = game.name || "Mini Warior"; 。這時候如果game.name獲取為null值或undefined值,gameName也會被賦值為你所希望的初始值,而不會影響接下來程式碼的執行。如果我們嘗試從undefined的屬性中取值,例如 var gameQualiPlayer = game.qualification.player; ,JavaScript將會丟擲一個“TypeError”的錯誤,我們也可以巧用&&運算子: var gameQualiPlayer = game.qualification && game.qualification.player; 避免錯誤,但結果仍然是取出一個undefined值。
處理一些不需要的屬性(例如原型鏈上的屬性)時,我們除了使用typeof關鍵字以外,還有一種辦法是使用Object.prototype.hasOwnProperty()方法。這個方法會返回布林值,值為填入的引數是否在當前的物件中。比較常用的用法是在使用for in語句遍歷物件時,for in語句預設會遍歷到原型鏈上的屬性。假如在開發過程中原型鏈上的屬性被其他人修改,而你不清楚,就會發生莫名的錯誤。因此在使用for in語句時使用這個方法會更為保險:
1 var player = { 2 name: 'Lyn', 3 age: 19, 4 gender: 'male' 5 }; 6 7 var playerPropertyName = []; 8 var playerProperty = []; 9 10 for(var key in player) { 11 playerPropertyName.push(i); 12 playerProperty.push(player[i]); 13 }
上面這段程式碼把player中的屬性的鍵存入playerPropertyName陣列,把player屬性的值存入playerProperty陣列中。下面在player原型鏈上加入新的屬性,並使用Object.prototype.hasOwnProperty()過濾:
1 var player = { 2 name: 'Lyn', 3 age: 19, 4 gender: 'male' 5 }; 6 player.prototype.playGame = 'Mini Warior'; 7 8 var playerPropertyName = []; 9 var playerProperty = []; 10 11 for (var key in player){ 12 if(player.hasOwnProperty(key){ 13 playerPropertyName.push(i); 14 playerProperty.push(player[i])' 15 } 16 }
這樣,在遍歷過程中,就不會把playGame的鍵和值存到對應陣列裡面。
物件的屬性有的可列舉,有的不可列舉。像我們上面這樣使用for in語句遍歷一個物件時,所有可列舉的屬性或方法都會受到影響,因此我們提到可以使用typeof關鍵字或hasOwnProperty方法進行過濾。但我們知道,JavaScript中Array也是物件,我們建立陣列,輸出它,會發現陣列的下標是鍵,值是值,還有一個不可列舉的length屬性(當然還有原型)。在這種情況下,我們使用for in語句就不會影響到length屬性。for in語句不僅容易遍歷到方法和原型屬性,還無法控制屬性名的順序,因此我們遍歷的最佳實踐應該是使用普通的for語句而不是for in語句(當然,當講到閉包時,我們也會發現for語句也並不是完美的,但至少它在大多數情況下都比for in遍歷要好)。
至於物件屬性的刪除,我們會使用到delete運算子,需要注意的一點就是它將不會觸及到原型鏈裡的內容,但刪除此物件的屬性後,可能會讓原型鏈的屬性浮現:假設我們有一個player物件,它有一個屬性nickname: "Lyn",它的原型上也有一個屬性nickname: "Ben",經過 delete player.nickname; 後,輸出player.nickname的值為Ben。
物件幫助我們編寫可擴充套件、可重用、高質量的JavaScript庫。但當然,物件還有幾個重要的概念是原型鏈和物件的建立,它值得我們放到一篇新的部落格中講述。