HTML5 API 全部都必須使用 JavaScript 撰寫來實現。JavaScript 基礎中又屬最要的一部份,若基本的不了解對之後的學習與運用一定會無法在進行。
萬物皆物件
在 JavaScript 的世界裡,除了非常少數核心部分,廣義而言,可以說萬物階物件(Object),如:
- Number (數字是物件)
- String (字串是物件)
- Boolean (布林是物件)
- Object (物件是物件)
- Function (函式是物件)
- Array (陣列是物件)
- Date (日期是物件)
- regExp (正規表達式是物件)
- Null (空是物件)
- Undefined (未定義是物件)
- Error (錯誤是物件)
「萬物階物件」,用物件的角度來看事情,先不要管它是個什麼東西,它就物件,很多時候問題會簡單很多。
null 與 undefined
null(空),是一種無數值的情況。undefined(未定義),是一種未初始化的情況。
1 2 | var a; // undefined var b = null; // null |
a 是未定義;b 是空。宣告一個變數但未指定值,那是未定義不是空。
空是一種狀態。我們常在 for 迴圈內使用 return 來跳離迴圈,return 未指定值,那是未定義不是空。
&& 與 || 運算子在判斷條件
&& (and) 與 || (or) 運算子在判斷條件時,第二個條件是否執行依第一個條件來決定。這用來存取一個物件的屬性前檢查物件是否為空非常有用。
1 2 3 4 5 6 7 8 9 10 | // 跨瀏覽器處理 var event = window || window.event; // 1. person 物件不為 null // 2. 取出 person.getName() 的值 var name = person && person.getName(); // 1. person 物件為 null // 2. 指定 "無" 為預設值 var englishName = person || "無"; |
物件
JavaScript 裡的物件是字典(name-value pair),name 的部分必須是字串, value 可以是任何 JavaScript 的值。JavaScript 的值就是好玩的地方,因為可放任何 JavaScript 的值,所以物件裡可以放物件,還記得第一點嗎,萬物皆物件,到了這裡可以再加一句,萬物皆可放。
1 2 3 4 5 6 7 8 9 10 11 | // 意義上,objA 與 objB 是相等,都是產生一個空物件。 // 實務上都會使用實體語法,尤其是在物件及陣列 var objA = new Object(); var objB = {}; // 實體語法(object literal) // 意義上,兩種存取語法是相同的 objB.boyName = "Bruce"; // 存 var manName = objB.boyName; // 取 objB["girlName"] = "Sherry"; // 存 var womanName = objB["girlName"]; // 取 |
第二種用法有個優點,屬性的名稱是以字串提供,當你將屬性設定為 JavaScript 關鍵字時,第二種存取方法不會出錯,第一種 . (點)物件存取是不可以使用 JavaScript 關鍵字。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 直接進行屬性初始化 // 格式 name : value var food = { name: "紅蘿蔔", "for": "Happy", details: { // 物件裡的物件 color : "red", price : 23, } }; // 一層一層存取即可 var foodColor = food.details.color; |
name,”for” 是屬性,for 是關鍵字,用 “for” 表示它是單純字串,details 是個物件,color,price 是屬性。實務上,我們會把物件屬性名稱都用字串表示,這在未來撰寫 JSON 相關應用時,可以用一致的習慣來撰寫,這裡是為了展示物件範例才未加上。
陣列
陣列的運作和物件很像。
1 2 | var arrA = new Array(); var arrB = []; // 實體語法 |
{} 與 [] 都是實體語法,實務上我們也大多使用實體語法是撰寫 JavaScript 程式碼。陣列好玩的地方在它有個物件沒有的屬性 length (長度)。
1 2 3 4 5 6 7 | // 直接進行陣列初始化 var arrC = ["Dog", "Cat", "Fish", "Bird"]; console.log(arrC.length); // 4 var arrD = ["Dog", "Cat", "Fish", "Bird"]; arrD[14] = "Money"; // 14 說給我錢,其他免談 arrD.length; // 15 |
第二範例的 arrD 讓我們瞭解二件事,一是 JavaScript 的陣列隨時可變,而且會自動調整至 index 指定的大小。二是 length 的回傳值是最高 Index 值加一。JavaScript 的索引是由 0 開始,length 是回傳項目個數,它不管項目是否有值。如果我們查取一個不存在的陣列,得到會是未定義(undefined),說到這裡是否瞭解 null 和 undefinded 差異了。
1 | console.log(typeof(arrD[33])); // undefined |
前面我們瞭解到 length 的回傳值是最高 Index 值加一,利用此特性,我們可以在陣列的最尾端加入項目:
1 | arrD[arrD.length] = "Ant"; // 相等 arrD.push("Ant"); |
這可以說是最安全有順序加入陣列的方式。
陣列迴圈處理
我們經常使用迴圈來取陣列的值。
1 2 3 | for (var i=0; i < arrD.length; i++){ // Do something } |
注意這裡「i < arrD.length」,程式每判斷一次就必須去取出 arrD.length 一次,這不是很呆嗎?應該這樣做:
1 2 3 | for (var i=0, len=arrD.length; i<len ; i++){ // Do something } |
我們先取出 arrD.length 的值讓它成為 len 變數,接下來只要拿 len 來進行判斷,程式馬上加速。另外還可以再加以變型:
1 2 3 | for (var i=0, value; value = arrD[i]; i++){ // Do something } |
這是利用 for 迴圈執行前會先測試條件( value = arrD[i] )是否為真,成功,便執行迴圈。執行順序為:
- 初始變數
- 測試 arrD[i] 是否有值
- arrD[i] 有值,進行取值及設定給變數 value,執行 for 迴圈
- arrD[i] 無值,離開 for 迴圈
第二步是重點,它的使用比第二種 len=arrD.length 更直接也更快,第二種方式因是必須在 for 迴圈內再進行一次取值處理的動作。不過此技巧有個小限制,你必須非常確定陣列裡不會有「假值」,例如,可能含有數字 0、空字串、陣列裡的物件、DOM 節點 … 有的話,還是使用第二種來處理。