面對對象的程序設計
面向對象(Object-Oriented, OO)的語言有一個標誌,那就是它們都有類的概念,而通過類可
以創建任意多個具有相同屬性和方法的對象。
一、理解對象:
第一種:基於Object對象
1 var person = new Object(); 2 person.name = "Nicholas"; 3 person.age = 29; 4 person.job = "Software Engineer"; 5 person.sayName = function(){ 6 alert(this.name); 7 };
第二種:對象字面量方式(比較清楚的查找對象包含的屬性及方法)
1 var person = { 2 name: "Nicholas",
age: 29, 4 job: "Software Engineer", 5 sayName: function() { 6 alert(this.name); 7 } 8 };
二、對象屬性類型
ECMA-262 第 5 版在定義只有內部才用的特性(attribute)時,描述了屬性(property)的各種特征 。ECMAScript中有兩種屬性:數據屬性和訪問器屬性。
1、數據屬性:
數據屬性指包含一個數據值的位置,可在該位置讀取或寫入值,該屬性有4個供述其行為的特性: [[configurable]]:表示能否使用delete操作符刪除從而重新定義,或能否修改為訪問器屬性。默認為true; [[Enumberable]]:表示是否可通過for-in循環返回屬性。默認true; [[Writable]]:表示是否可修改屬性的值。默認true; [[Value]]:包含該屬性的數據值。讀取/寫入都是該值。默認為undefined;如上面實例對象person中定義了name屬性,其值為“Nicholas”,對該值的修改都反正在這個位置 要修改對象屬性的默認特征(默認都為true),可調用Object.defineProperty()方法,它接收三個參數:屬性所在對象,屬性名和一個描述符對象(必須是:configurable、enumberable、writable和value,可設置一個或多個值)。1var person = {}; 2 Object.defineProperty(person, "name", { 3 configurable: false, 4 value: "Nicholas" 5 }); 6 alert(person.name); //"Nicholas" 7 delete person.name; 8 alert(person.name); //"Nicholas"
把 configurable 設置為 false,表示不能從對象中刪除屬性。如果對這個屬性調用 delete,則在非嚴格模式下什麽也不會發生,而在嚴格模式下會導致錯誤。而且,一旦把屬性定義為不可配置的,就不能再把它變回可配置了。此時,再調用 Object.defineProperty()方法修改除 writable 之外的特性,都會導致錯誤.
在調用 Object.defineProperty()方法時,如果不指定, configurable、 enumerable 和
writable
特性的默認值都是 false。
2、訪問器屬性:
它主要包括一對getter和setter函數,在讀取訪問器屬性時,會調用getter返回有效值;寫入訪問器屬性時,調用setter,寫入新值;該屬性有以下4個特征: [[Configurable]]:是否可通過delete操作符刪除重新定義屬性; [[Numberable]]:是否可通過for-in循環查找該屬性; [[Get]]:讀取屬性時調用,默認:undefined; [[Set]]:寫入屬性時調用,默認:undefined; 訪問器屬性不能直接定義,必須使用defineProperty()來定義,如下:1 var book = { 2 _year: 2004, 3 edition: 1 4 }; 5 Object.defineProperty(book, "year", { 6 get: function() { 7 return this._year; 8 }, 9 set: function(newValue) { 10 if(newValue > 2004) { 11 this._year = newValue; 12 this.edition += newValue - 2004; 13 } 14 } 15 }); 16 book.year = 2005; 17 alert(book.edition); //2
以上代碼創建了一個 book 對象,並給它定義兩個默認的屬性: _year 和 edition。 _year 前面的下劃線是一種常用的記號,用於表示只能通過對象方法訪問的屬性。而訪問器屬性 year 則包含一個getter 函數和一個 setter 函數。 getter 函數返回_year 的值, setter 函數通過計算來確定正確的版本。因此,把 year 屬性修改為 2005 會導致_year 變成 2005,而 edition 變為 2。這是使用訪問器屬性的常見方式,即設置一個屬性的值會導致其他屬性發生變化。
三、創建對象
雖然 Object 構造函數或對象字面量都可以用來創建單個對象,但這些方式有個明顯的缺點:使用同一個接口創建很多對象,會產生大量的重復代碼。為解決這個問題,人們開始使用工廠模式的一種變體。
1、工廠模式
工廠模式是軟件工程領域一種廣為人知的設計模式,這種模式抽象了創建具體對象的過程(本書後面還將討論其他設計模式及其在 JavaScript 中的實現)。考慮到在 ECMAScript 中無法創建類,開發人員就發明了一種函數,用函數來封裝以特定接口創建對象的細節,如下面的例子所示。
1 function createPerson(name, age, job) { 2 var o = new Object(); 3 o.name = name; 4 o.age = age; 5 o.job = job; 6 o.sayName = function() { 7 alert(this.name); 8 }; 9 return o; 10 } 11 var person1 = createPerson("Nicholas", 29, "Software Engineer"); 12 var person2 = createPerson("Greg", 27, "Doctor");
工廠模式雖然解決了創建多個相似對象的問題,但卻沒有解決對象識別的問題(即怎樣知道一個對象的類型)。
2、構造函數模式
1 function Person(name, age, job) { 2 this.name = name; 3 this.age = age; 4 this.job = job; 5 this.sayName = function() { 6 alert(this.name); 7 }; 8 } 9 var person1 = new Person("Nicholas", 29, "Software Engineer"); 10 var person2 = new Person("Greg", 27, "Doctor");
使用自定義的構造函數(與普通函數一樣,只是用它來創建對象),定義對象類型(如:Person)的屬性和方法。它與工廠方法區別在於:
- 沒有顯式地創建對象
- 直接將屬性和方法賦值給this對象;
- 沒有return語句;
此外,要創建Person的實例,必須使用new關鍵字,以Person函數為構造函數,傳遞參數完成對象創建;實際創建經過以下4個過程:
- 創建一個對象
- 將函數的作用域賦給新對象(因此this指向這個新對象,如:person1)
- 執行構造函數的代碼
- 返回該對象
未完待續,後期再補
面對對象的程序設計