js物件導向設計---建立物件的方式
一、Object建構函式或物件字面量
const obj = new Object();
const obj1={
name: 'xxx'
}
- 缺點: 使用同一個介面建立很多物件,會產生大量的重複程式碼。
二、工廠模式
function createPerson(name, age, job){
const o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){ alert(this.name); };
return o;
}
const person1 = createPerson("Nicholas", 29, "Software Engineer");
函式createPerson()能夠根據接受的引數來構建一個包含所有必要資訊的Person物件。可以無數次地呼叫這個函式,而每次它都會返回一個包含三個屬性一個方法的物件。
- 優點:然解決了建立多個相似物件的問題
- 缺點:沒有解決物件識別的問題(即怎樣知道一個物件的型別)
三、建構函式模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
const person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
- 建構函式始終都應該以一個大寫字母開頭.
- 建構函式與其他函式的唯一區別,就在於呼叫它們的方式不同。
要建立Person的新例項,必須使用new操作符。以這種方式呼叫建構函式實際上會經歷以下4個步驟:
(1)建立一個新物件;
(2)將建構函式的作用域賦給新物件(因此this就指向了這個新物件);
(3)執行建構函式中的程式碼(為這個新物件新增屬性);
(4)返回新物件。
person1和person2分別儲存著Person的一個不同的例項。這兩個物件都有一個constructor(建構函式)屬性,該屬性指向Person,如下所示。
alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true
alert(person1 instanceof Object); // true
alert(person1 instanceof Person); // true
alert(person2 instanceof Object); // true
alert(person2 instanceof Person); // true
缺點:每個方法都要在每個例項上重新建立一遍。不是同一個Function的例項
建立兩個完成同樣任務的Function例項的確沒有必要;
況且有this物件在,根本不用在執行程式碼前就把函式繫結到特定物件上面。
因此,大可像下面這樣,通過把函式定義轉移到建構函式外部來解決這個問題。
function sayName()
alert(this.name);
};
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName
}
新問題:在全域性作用域中定義的函式實際上只能被某個物件呼叫,這讓全域性作用域有點名不副實。而更讓人無法接受的是:如果物件需要定義很多方法,那麼就要定義很多個全域性函式,於是我們這個自定義的引用型別就絲毫沒有封裝性可言了。好在,這些問題可以通過使用原型模式來解決。
四、原型模式
我們建立的每個函式都有一個prototype(原型)屬性,這個屬性是一個指標,指向一個物件,而這個物件的用途是包含可以由特定型別的所有例項共享的屬性和方法。
function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
const person1 = new Person();
//"Nicholas"person1.sayName();var person2 = new Person();
- 優點: 可以讓所有物件例項共享它所包含的屬性和方法。
- 缺點:它省略了為建構函式傳遞初始化引數這一環節,結果所有例項在預設情況下都將取得相同的屬性值。原型模式的最大問題是由其共享的本性所導致的。原型中所有屬性是被很多例項共享的,這種共享對於函式非常合適。對於那些包含基本值的屬性倒也說得過去,通過在例項上新增一個同名屬性,可以隱藏原型中的對應屬性。然而,對於包含引用型別值的屬性來說,問題就比較突出了。
function Person(){}
Person.prototype = {
constructor: Person,
name : "Nicholas",
age : 29,
job : "Software Engineer",
friends : ["Shelby", "Court"],
sayName() { console.log(this.name);}
};
var person1 = new Person();
var person2 = new Person();person1.friends.push("Van");
//"Shelby,Court,Van"
console.log(person1.friends);
//"Shelby,Court,Van"
console.log(person2.friends);
//true
console.log(person1.friends === person2.friends);
四、組合使用建構函式模式和原型模式
目前在ECMAScript中使用最廣泛、認同度最高的一種建立自定義型別的方法。
建立自定義型別的最常見方式,就是組合使用建構函式模式與原型模式。
- 1.建構函式模式用於定義例項屬性,
- 2.原型模式用於定義方法和共享的屬性。結
每個例項都會有自己的一份例項屬性的副本,但同時又共享著對方法的引用,最大限度地節省了記憶體。另外,這種混成模式還支援向建構函式傳遞引數
function Person(name, age, job){ this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){ alert(this.name); }
}
const person1 = new Person("Nicholas", 29, "Software Engineer");
const person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends);//"Shelby,Count,Van"
alert(person2.friends);//"Shelby,Count"
alert(person1.friends === person2.friends);//false
alert(person1.sayName === person2.sayName);//true
五、動態原型模式
把所有資訊都封裝在了建構函式中,而通過在建構函式中初始化原型(僅在必要的情況下),又保持了同時使用建構函式和原型的優點。換句話說,可以通過檢查某個應該存在的方法是否有效,來決定是否需要初始化原型。
function Person(name, age, job){ //屬性
this.name = name;
this.age = age;
this.job = job;
//方法
if (typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}
const friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();
使用動態原型模式時,不能使用物件字面量重寫原型。前面已經解釋過了,如果在已經建立了例項的情況下重寫原型,那麼就會切斷現有例項與新原型之間的聯絡。
六 寄生建構函式模式
基本思想是建立一個函式,該函式的作用僅僅是封裝建立物件的程式碼,然後再返回新建立的物件;
function Person(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
const friend = new Person("Nicholas", 29, "Software Engineer");
//"Nicholas"
friend.sayName();
返回的物件與建構函式或者與建構函式的原型屬性之間沒有關係;
七 穩妥建構函式模式
所謂穩妥物件,指的是沒有公共屬性,而且其方法也不引用this的物件。穩妥物件最適合在一些安全的環境中(這些環境中會禁止使用this和new),或者在防止資料被其他應用程式(如Mashup程式)改動時使用。穩妥建構函式遵循與寄生建構函式類似的模式,但有兩點不同:一是新建立物件的例項方法不引用this;二是不使用new操作符呼叫建構函式。
function Person(name, age, job){
//建立要返回的物件
var o = new Object();
//可以在這裡定義私有變數和函式
//新增方法
o.sayName = function(){
alert(name);
};
//返回物件
return o;
注意,在以這種模式建立的物件中,除了使用sayName()方法之外,沒有其他辦法訪問name的值。可以像下面使用穩妥的Person建構函式。
var friend = Person("Nicholas", 29, "Software Engineer");
//"Nicholas"
friend.sayName();
這樣,變數person中儲存的是一個穩妥物件,而除了呼叫sayName()方法外,沒有別的方式可以訪問其資料成員。
參考文獻:《javascript 高階程式設計 第三版》
相關文章
- JS物件導向設計-建立物件JS物件
- JS物件導向程式設計(一):物件JS物件程式設計
- JS物件導向的程式設計JS物件程式設計
- JS物件導向設計模式JS物件設計模式
- js物件導向程式設計JS物件程式設計
- 物件導向-設計模式-建立型物件設計模式
- [寫作中...]Js物件導向(2): 建立物件JS物件
- iOS 開發之 OOA (物件導向分析) & OOD (物件導向設計)& OOP (物件導向程式設計)iOS物件OOP程式設計
- JS物件導向程式設計(三):原型JS物件程式設計原型
- JavaScript物件導向—物件的建立和操作JavaScript物件
- JS物件導向JS物件
- js建立物件的方式JS物件
- 物件導向程式設計物件程式設計
- JS物件導向程式設計(四):繼承JS物件程式設計繼承
- js-物件導向-設計模式-命令模式JS物件設計模式
- Js物件導向(1): 理解物件JS物件
- 物件導向的思維方式物件
- Scala的物件導向程式設計物件程式設計
- javascript:物件導向的程式設計JavaScript物件程式設計
- 物件導向的設計原則物件
- 理解Js中物件導向程式設計的繼承JS物件程式設計繼承
- [.net 物件導向程式設計基礎] (2) 關於物件導向程式設計物件程式設計
- ExtJS物件導向JS物件
- js物件導向程式設計:如何定義常量?JS物件程式設計
- 十三、物件導向程式設計物件程式設計
- 程式設計思想 物件導向程式設計物件
- Java--物件導向設計Java物件
- 十六、物件導向程式設計物件程式設計
- 物件導向系統設計物件
- 物件導向設計與DROOLS物件
- perl 物件導向程式設計物件程式設計
- LotusScript物件導向程式設計物件程式設計
- Javascript 物件導向程式設計JavaScript物件程式設計
- 物件導向——類設計(一)物件
- 物件導向設計原則物件
- 物件導向-物件導向思想物件
- [筆記]物件導向的程式設計筆記物件程式設計
- 物件導向的基本設計原則物件