本篇主要討論了通過字面量以構造對象的方法,比如對象、數組以及正則表達式等字面量的構造方法,同時還討論了與類似Object()和Array()等內置構造函數相比,為什么基於字面量表示法是更為可取。
對象字面量
JavaScript中並沒有類的概念,正如其他動態語言一樣,JavaScript中的所有元素均為對象。我們可以把JavaScript中的對象看做是其他語言中的HashTable,即鍵-值對(key-value pair)哈希表。
在JavaScript中所創建的自定義對象在任何時候都是可變的,你可以在任何時間添加或刪除對象的屬性和方法。考慮以下例子:
// 定義一個空對象 var dog = {}; // 向dog對象添加一個屬性 dog.name = "Ben"; // 向dog對象添加一個方法 dog.getName = function () { return dog.name; };
上例中,dog對象開始時是處於“干凈”狀態,即一個空對象。然后向該對象添加了一個屬性和一個方法。此外在程序生命周期內的任何時候,都可以執行一下操作:
改變屬性和方法的值,如下所示:
dog.getName = function () { // 重新定義該方法 return "Max"; };
完全刪除屬性或方法:
delete dog.name;
添加更多的屬性和方法:
dog.say = function () { return "Hello"; }; dog.fleas = true;
以下是一種語法更為簡潔的對象字面量模式,你可在創建對象時向其添加屬性和方法,如下所示:
var dog = { name: "Max", getName = function () { return this.name; } };
對象字面量語法
1. 將對象包裝在大括號中;
2. 對象中以逗號分隔鍵值對;
3. 用冒號分隔屬性名和屬性值;
4. 不要忘記最后大括號后的分號。
自定義構造函數
除了對象字面量模式,可以使用自己的構造函數來創建對象,如下所示:
var max = new Person("Max"); max.say(); // 輸出"I am Max"
這種模式看起來很像Java中使用一個名為Person的類創建一個對象,但實際上正如本篇開頭所說,JavaScript中並沒有類,Person只不過是一個函數而已。
以下是Person構造函數的定義:
var Person = function (name) { this.name = name; this.say = function () { return "I am " + this.name; }; };
使用new操作符調用構造函數(Person方法)時,函數內部會發生以下微妙的變化:
1. 創建一個空對象並且this變量引用了該變量,同時還繼承了該函數的原型;
2. 屬性和方法被加入到this引用的對象中;
3. 新創建的對象由this所引用,並且最后隱式地返回this(如果沒有顯示地返回其他對象)。
所以使用new操作符調用構造函數時,Person函數看起來會變成如下這樣:
var Person = function (name) { // 使用字面量模式創建一個新對象 var this = {}; // 向this添加屬性和方法 this.name = name; this.say = function () { return "I am " + this.name; }; return this; };
需要注意的是,如果在調用構造函數時忘記使用new操作符,函數中的this將會指向全局對象(在瀏覽器中,this將會指向window),這回帶來錯誤的構造結果。
數組字面量
JavaScript中的數組也是對象,且數組字面量表示法更為簡單,更可取,如下所示:
var a = ["max", "allen", "gao"]; console.log(typeof a); // 輸出"object" console.log(a.constructor === Array); // 輸出true
JSON
JSON代表了JavaScript對象表示(JavaScript Object Notation)以及數據傳輸格式,它是一種輕量級數據交換格式。
實際上JSON只是一個數組和對象字面量表示法的組合,下面是一個JSON字符串的例子:
{"name": "value", "some": [1, 2, 3]}
注意JSON中的屬性名需要包裝在引號內。
使用JSON
有一系列方法用來在JSON字符串和對象之間相互轉換,如下所示:
// 從JSON字符串轉為對象 var jstr = '{"mykey": "my value"}'; var data = JSON.parse(jstr); console.log(data.mykey); // "my value" // 從對象轉為JSON字符串 var dot = { name: "Max", dob: new Date(), legs: [1, 2, 3, 4] }; var jsonstr = JSON.stringify(dog); // jsonstr is: // {"name":"Max","dob":"2013-12-30T12:40:32:198","legs":[1,2,3,4]}
正則表達式字面量
JavaScript中的正則表達式也是對象,可以通過new RegExp()和正則表達式字面量兩種方法創建正則表達式。
通常情況下,建議優先使用正則表達式字面量方式,如下所示:
var re = /[a-z]/gm;
如果匹配模式需要動態生成,則可用new RegExp()方式創建正則表達式,如下所示:
var re = new RegExp("[a-z]", "gm");
正則表達式字面量語法
正則表達式字面量語法使用了斜杠來包裝用於匹配的正則表達式模式。第二個斜杠后,可以將該模式修改為不加引號的字母形式:
g:全局匹配;
m:多行;
i:大小寫敏感。
模式修改器可以以任何順序或者組合方式出現:
var re = /patterm/gmi;
當調用類似String.prototype.replace()的方法以接受正則表達式作為參數時,使用正則表達式字面量有助於編寫出更簡潔的代碼。
var no_letters = "abc123XYZ".replace(/[a-z]/gi, ""); console.log(no_letters); // 輸出123
錯誤對象
JavaScript中有一些內置錯誤構造函數,比如Error(), SyntaxError(), TypeError()以及其他,這些處錯誤構造函數都帶有throw語句。通過這些錯誤構造函數創建的錯誤對象具有下列屬性:
name:用於創建對象的構造函數的名稱屬性,它可以是一般的”Error“或者更為專門的構造函數,比如”RangeError“。
message:當創建對象時傳遞給構造函數的字符串。
另一方面,throw適用於任何對象,並不一定是由某個錯誤構造函數所創建的對象,因此可以選擇拋出自己的對象。這種錯誤對象也可以有屬性”name“、”message“,以及任意希望傳遞給catch語句來處理的其他類型的信息。當設計自定義錯誤對象時,可以發揮創造性,並且用這些錯誤對象來將應用程序的狀態恢復到正常狀態。
try { throw { name: "MyErrorType", message: "oops", extra: "This was rather embrassing", remedy: genericErrorHandler }; } catch (e) { alert(e.message); e.remedy(); }
小節
本篇中,我們已經學習到不同的字面量模式,相比構造函數,這些都是更為簡單的替代方法。本篇主要討論了下列主題:
1. 對象字面量表示法是一種優美的對象創建方式,它以包裝在大括號中的逗號分隔的鍵值對(key-value pair)的方式創建對象;
2. 自定義構造函數;
3. 數組字面量表示法;
4. JSON
5. 正則表達式字面量
6. 錯誤對象
在一般情況下,除了Date()構造函數以外,很少使用其他內置構造函數。下面的表格總結了這些構造函數及其相應的優先選擇的字面量模式:
內建構造函數(避免使用) | 字面量模式(推薦) |
var o = new Object(); | var o = {}; |
var a = new Array(); | var a = []; |
var re = new RegExp("[a-z]", "g"); | var re = /[a-z]/g; |
var s = new String(); | var s = ""; |
var n = new Number(); | var n = 0; |
var b = new Boolean(); | var b = false; |
throw new Error("un-oh"); | throw { name: "Error", message: "uh-oh" } or throw Error("un-oh"); |