## 問一、引入工廠,解決重復代碼
前面已經提到,JS中創建對象的方法,不難發現,基本的創建方法中,創建一個對象還算簡單,如果創建多個類似的對象的話就會產生大量重復的代碼。?
解決:工廠模式方法(添加一個專門創建對象的方法,傳入參數避免重復)
~~~
function createObject(name,age){
var obj =new Object(); //創建對象
obj.name = name;
obj.age = age;
obj.run = function(){
return this.name + this.age + '處理中...';
};
return obj; //返回對象引用
};
~~~
## 問二、引入構造函數,解決對象識別
上面方法雖然解決了避免重復代碼出現的問題,但也帶來了無法識別具體對象的問題,方法內部使用new Object的方式,最后返回該對象引用,調用該方法創建的對象返回的全部都是Object的引用,因此使用typeof或instanceof操作符時都無法區分具體對象。
解決:構造函數(改良后的工廠方法)
~~~
function Box(name,age){ //創建對象
this.name = name;
this.age = age;
this.run = function(){
return this.name + this.age + '處理中...';
};
};
~~~
比較:細心的童鞋就該發現了,該方法與問一中的工廠模式不同之處就在于:省略了newObject()的明文執行過程;省略了return語句,這些都由后臺自動執行。
而構造函數區別普通函數的地方在于其調用方式,必須用new運算符或對象冒充方式調用。
## 問三、引入prototype屬性對象,解決對象之間的共享問題
每一個對象都會有一個prototype,同時它也是一個對象。使用目的是為了解決共享問題,調用同一個構造函數創建的該對象會共享prototype中的屬性和方法。
解決:使用原型模式解決共享
~~~
function Box() {} //聲明一個構造函數
Box.prototype.name = 'Lee'; //在原型里添加屬性
Box.prototype.age = 100;
Box.prototype.run = function () { //在原型里添加方法
return this.name + this.age + '處理中...';
};
~~~
比較:
構造函數創建

使用原型創建

細節:在調用屬性或方法時,采用就近原則,先查找實例中是否存在,否的話查找原型,可使用isPrototypeOf(),hasOwnPrototy(),in操作符進行相關測試。
## 問四、使用組合,解決共享及傳參
原型模式創建對象省略了構造函數傳參初始化的過程,這既是它的缺點又是它的優點,缺點是對象初始化的值一樣,并且如果原型屬性中包含有引用類型,則對一個對象進行更改,其他對象的對應屬性也會跟著更改了。
解決:組合構造函數+原型模式(解決共享和傳參的問題)
~~~
function Box(name, age) { //不共享的使用構造函數
this.name = name;
this.age = age;
this. family = ['父親', '母親', '妹妹'];
};
Box.prototype = { //共享的使用原型模式
constructor : Box,
run : function () {
return this.name + this.age + this.family;
}
};
~~~
細節:這種方式其實就是將構造函數與原型一起使用,對要創建的對象分析,將需要共享的內容放入原型中,不需要的則放在構造函數里。這樣也就是組合了。
優化:這樣分開式的寫法難免有些怪異,我們將這兩部分合并
動態原型模式(第一次調用共享方法時進行初始化原型,以后就不會初始化了)
~~~
function Box(name ,age) { //將所有信息封裝到函數體內
this.name = name;
this.age = age;
if (typeof this.run != 'function') {//僅在第一次調用的初始化
Box.prototype.run = function () {
return this.name +this.age + '處理中...';
};
}
}
~~~
## 中結:
在學習JS中,還是很需要對正統面向對象語言的理解的,在這里我們學習了使用構造函數以及原型來創建對象,理解了二者的概念,對于后面的JS中面向對象深入學習會很有幫助,各種不同的創建方式是為了解決不同情況的問題,理解了這些才能按需使用。